From c6268803a398ef114d86e60d7ead70b517262df6 Mon Sep 17 00:00:00 2001 From: Harsh Rawat Date: Fri, 17 Apr 2026 16:53:46 +0530 Subject: [PATCH 1/3] Add live migration ttrpc service definition Introduces the Live Migration ttrpc service with RPCs for preparing, transferring memory, and finalizing sandbox live migration between source and destination hosts. Includes sandbox state serialization for cross-host config propagation. Signed-off-by: Harsh Rawat --- Protobuild.toml | 1 + pkg/migration/doc.go | 4 + pkg/migration/migration.pb.go | 817 ++++++++++++++++++++++++++ pkg/migration/migration.proto | 104 ++++ pkg/migration/migration_options.pb.go | 482 +++++++++++++++ pkg/migration/migration_options.proto | 60 ++ pkg/migration/migration_ttrpc.pb.go | 173 ++++++ 7 files changed, 1641 insertions(+) create mode 100644 pkg/migration/doc.go create mode 100644 pkg/migration/migration.pb.go create mode 100644 pkg/migration/migration.proto create mode 100644 pkg/migration/migration_options.pb.go create mode 100644 pkg/migration/migration_options.proto create mode 100644 pkg/migration/migration_ttrpc.pb.go diff --git a/Protobuild.toml b/Protobuild.toml index 1e34eb92f1..48d04ea350 100644 --- a/Protobuild.toml +++ b/Protobuild.toml @@ -21,5 +21,6 @@ prefixes = [ "github.com/Microsoft/hcsshim/internal/computeagent", "github.com/Microsoft/hcsshim/internal/ncproxyttrpc", "github.com/Microsoft/hcsshim/internal/vmservice", + "github.com/Microsoft/hcsshim/pkg/migration", ] generators = ["go", "go-ttrpc"] diff --git a/pkg/migration/doc.go b/pkg/migration/doc.go new file mode 100644 index 0000000000..28df60e9e9 --- /dev/null +++ b/pkg/migration/doc.go @@ -0,0 +1,4 @@ +// Package migration contains the proto and compiled go files for the live +// migration service, which manages sandbox live migration workflows including +// preparation, memory transfer, and finalization. +package migration diff --git a/pkg/migration/migration.pb.go b/pkg/migration/migration.pb.go new file mode 100644 index 0000000000..05592f06eb --- /dev/null +++ b/pkg/migration/migration.pb.go @@ -0,0 +1,817 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc v5.26.0 +// source: github.com/Microsoft/hcsshim/pkg/migration/migration.proto + +package migration + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + anypb "google.golang.org/protobuf/types/known/anypb" + durationpb "google.golang.org/protobuf/types/known/durationpb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// FinalizeAction specifies the action to take on the sandbox during finalization. +type FinalizeAction int32 + +const ( + // No action specified; the server should treat this as an error or use a default. + FinalizeAction_FINALIZE_ACTION_UNSPECIFIED FinalizeAction = 0 + // Stop and clean up the sandbox. + FinalizeAction_FINALIZE_ACTION_STOP FinalizeAction = 1 + // Resume the sandbox (used on the destination to start running, or on the source to rollback). + FinalizeAction_FINALIZE_ACTION_RESUME FinalizeAction = 2 +) + +// Enum value maps for FinalizeAction. +var ( + FinalizeAction_name = map[int32]string{ + 0: "FINALIZE_ACTION_UNSPECIFIED", + 1: "FINALIZE_ACTION_STOP", + 2: "FINALIZE_ACTION_RESUME", + } + FinalizeAction_value = map[string]int32{ + "FINALIZE_ACTION_UNSPECIFIED": 0, + "FINALIZE_ACTION_STOP": 1, + "FINALIZE_ACTION_RESUME": 2, + } +) + +func (x FinalizeAction) Enum() *FinalizeAction { + p := new(FinalizeAction) + *p = x + return p +} + +func (x FinalizeAction) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (FinalizeAction) Descriptor() protoreflect.EnumDescriptor { + return file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_enumTypes[0].Descriptor() +} + +func (FinalizeAction) Type() protoreflect.EnumType { + return &file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_enumTypes[0] +} + +func (x FinalizeAction) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use FinalizeAction.Descriptor instead. +func (FinalizeAction) EnumDescriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_rawDescGZIP(), []int{0} +} + +type PrepareAndExportSandboxRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Idempotency key for the migration session (stable across retries). + SessionID string `protobuf:"bytes,1,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` + // Options for initializing the live migration on the source. + InitOptions *MigrationInitializeOptions `protobuf:"bytes,2,opt,name=init_options,json=initOptions,proto3" json:"init_options,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PrepareAndExportSandboxRequest) Reset() { + *x = PrepareAndExportSandboxRequest{} + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PrepareAndExportSandboxRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PrepareAndExportSandboxRequest) ProtoMessage() {} + +func (x *PrepareAndExportSandboxRequest) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PrepareAndExportSandboxRequest.ProtoReflect.Descriptor instead. +func (*PrepareAndExportSandboxRequest) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_rawDescGZIP(), []int{0} +} + +func (x *PrepareAndExportSandboxRequest) GetSessionID() string { + if x != nil { + return x.SessionID + } + return "" +} + +func (x *PrepareAndExportSandboxRequest) GetInitOptions() *MigrationInitializeOptions { + if x != nil { + return x.InitOptions + } + return nil +} + +type PrepareAndExportSandboxResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // An opaque config that should be set in the CreateSandbox input on the destination. + Config *anypb.Any `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PrepareAndExportSandboxResponse) Reset() { + *x = PrepareAndExportSandboxResponse{} + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PrepareAndExportSandboxResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PrepareAndExportSandboxResponse) ProtoMessage() {} + +func (x *PrepareAndExportSandboxResponse) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PrepareAndExportSandboxResponse.ProtoReflect.Descriptor instead. +func (*PrepareAndExportSandboxResponse) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_rawDescGZIP(), []int{1} +} + +func (x *PrepareAndExportSandboxResponse) GetConfig() *anypb.Any { + if x != nil { + return x.Config + } + return nil +} + +type ImportSandboxRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Idempotency key for the migration session (must match the key used on the source). + SessionID string `protobuf:"bytes,1,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` + // Opaque config produced by PrepareAndExportSandbox on the source. Forwarded + // verbatim by the caller; the destination service is responsible for decoding it. + Config *anypb.Any `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ImportSandboxRequest) Reset() { + *x = ImportSandboxRequest{} + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ImportSandboxRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ImportSandboxRequest) ProtoMessage() {} + +func (x *ImportSandboxRequest) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ImportSandboxRequest.ProtoReflect.Descriptor instead. +func (*ImportSandboxRequest) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_rawDescGZIP(), []int{2} +} + +func (x *ImportSandboxRequest) GetSessionID() string { + if x != nil { + return x.SessionID + } + return "" +} + +func (x *ImportSandboxRequest) GetConfig() *anypb.Any { + if x != nil { + return x.Config + } + return nil +} + +type ImportSandboxResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ImportSandboxResponse) Reset() { + *x = ImportSandboxResponse{} + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ImportSandboxResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ImportSandboxResponse) ProtoMessage() {} + +func (x *ImportSandboxResponse) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ImportSandboxResponse.ProtoReflect.Descriptor instead. +func (*ImportSandboxResponse) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_rawDescGZIP(), []int{3} +} + +type PrepareSandboxRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Idempotency key for the migration session (must match the key used on the source). + SessionID string `protobuf:"bytes,1,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` + // Options for initializing the live migration on the destination. + InitOptions *MigrationInitializeOptions `protobuf:"bytes,2,opt,name=init_options,json=initOptions,proto3" json:"init_options,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PrepareSandboxRequest) Reset() { + *x = PrepareSandboxRequest{} + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PrepareSandboxRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PrepareSandboxRequest) ProtoMessage() {} + +func (x *PrepareSandboxRequest) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PrepareSandboxRequest.ProtoReflect.Descriptor instead. +func (*PrepareSandboxRequest) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_rawDescGZIP(), []int{4} +} + +func (x *PrepareSandboxRequest) GetSessionID() string { + if x != nil { + return x.SessionID + } + return "" +} + +func (x *PrepareSandboxRequest) GetInitOptions() *MigrationInitializeOptions { + if x != nil { + return x.InitOptions + } + return nil +} + +type PrepareSandboxResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PrepareSandboxResponse) Reset() { + *x = PrepareSandboxResponse{} + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PrepareSandboxResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PrepareSandboxResponse) ProtoMessage() {} + +func (x *PrepareSandboxResponse) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PrepareSandboxResponse.ProtoReflect.Descriptor instead. +func (*PrepareSandboxResponse) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_rawDescGZIP(), []int{5} +} + +type TransferSandboxRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Idempotency key for migration session. + SessionID string `protobuf:"bytes,1,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` + // Max time to wait for socket/connection readiness before declaring TIMEOUT. + // If unset, server uses a sensible default (e.g., 10 minutes). + Timeout *durationpb.Duration `protobuf:"bytes,2,opt,name=timeout,proto3" json:"timeout,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TransferSandboxRequest) Reset() { + *x = TransferSandboxRequest{} + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TransferSandboxRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TransferSandboxRequest) ProtoMessage() {} + +func (x *TransferSandboxRequest) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TransferSandboxRequest.ProtoReflect.Descriptor instead. +func (*TransferSandboxRequest) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_rawDescGZIP(), []int{6} +} + +func (x *TransferSandboxRequest) GetSessionID() string { + if x != nil { + return x.SessionID + } + return "" +} + +func (x *TransferSandboxRequest) GetTimeout() *durationpb.Duration { + if x != nil { + return x.Timeout + } + return nil +} + +type TransferSandboxResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Increments per message; can be used to dedupe after client restarts. + MessageID uint32 `protobuf:"varint,1,opt,name=message_id,json=messageId,proto3" json:"message_id,omitempty"` + // Event-specific message from the migration notification. + Event string `protobuf:"bytes,2,opt,name=event,proto3" json:"event,omitempty"` + // Populated when event indicates an error or timeout. + Error string `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"` + // When the transfer started (according to the server). + StartTime *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"` + // When this update was produced. + UpdateTime *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=update_time,json=updateTime,proto3" json:"update_time,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TransferSandboxResponse) Reset() { + *x = TransferSandboxResponse{} + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TransferSandboxResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TransferSandboxResponse) ProtoMessage() {} + +func (x *TransferSandboxResponse) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TransferSandboxResponse.ProtoReflect.Descriptor instead. +func (*TransferSandboxResponse) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_rawDescGZIP(), []int{7} +} + +func (x *TransferSandboxResponse) GetMessageID() uint32 { + if x != nil { + return x.MessageID + } + return 0 +} + +func (x *TransferSandboxResponse) GetEvent() string { + if x != nil { + return x.Event + } + return "" +} + +func (x *TransferSandboxResponse) GetError() string { + if x != nil { + return x.Error + } + return "" +} + +func (x *TransferSandboxResponse) GetStartTime() *timestamppb.Timestamp { + if x != nil { + return x.StartTime + } + return nil +} + +func (x *TransferSandboxResponse) GetUpdateTime() *timestamppb.Timestamp { + if x != nil { + return x.UpdateTime + } + return nil +} + +type FinalizeSandboxRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Idempotency key for the session (must match the key used in PrepareSandbox). + SessionID string `protobuf:"bytes,1,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` + // Action to perform on the sandbox at finalize time. + Action FinalizeAction `protobuf:"varint,2,opt,name=action,proto3,enum=FinalizeAction" json:"action,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *FinalizeSandboxRequest) Reset() { + *x = FinalizeSandboxRequest{} + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *FinalizeSandboxRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FinalizeSandboxRequest) ProtoMessage() {} + +func (x *FinalizeSandboxRequest) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FinalizeSandboxRequest.ProtoReflect.Descriptor instead. +func (*FinalizeSandboxRequest) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_rawDescGZIP(), []int{8} +} + +func (x *FinalizeSandboxRequest) GetSessionID() string { + if x != nil { + return x.SessionID + } + return "" +} + +func (x *FinalizeSandboxRequest) GetAction() FinalizeAction { + if x != nil { + return x.Action + } + return FinalizeAction_FINALIZE_ACTION_UNSPECIFIED +} + +type FinalizeSandboxResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *FinalizeSandboxResponse) Reset() { + *x = FinalizeSandboxResponse{} + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *FinalizeSandboxResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FinalizeSandboxResponse) ProtoMessage() {} + +func (x *FinalizeSandboxResponse) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FinalizeSandboxResponse.ProtoReflect.Descriptor instead. +func (*FinalizeSandboxResponse) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_rawDescGZIP(), []int{9} +} + +type CreateDuplicateSocketRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Idempotency key; must match active LM session. + SessionID string `protobuf:"bytes,1,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` + // Serialized WSAProtocolInfo struct (opaque to clients). + ProtocolInfo []byte `protobuf:"bytes,2,opt,name=protocol_info,json=protocolInfo,proto3" json:"protocol_info,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateDuplicateSocketRequest) Reset() { + *x = CreateDuplicateSocketRequest{} + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateDuplicateSocketRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateDuplicateSocketRequest) ProtoMessage() {} + +func (x *CreateDuplicateSocketRequest) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateDuplicateSocketRequest.ProtoReflect.Descriptor instead. +func (*CreateDuplicateSocketRequest) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_rawDescGZIP(), []int{10} +} + +func (x *CreateDuplicateSocketRequest) GetSessionID() string { + if x != nil { + return x.SessionID + } + return "" +} + +func (x *CreateDuplicateSocketRequest) GetProtocolInfo() []byte { + if x != nil { + return x.ProtocolInfo + } + return nil +} + +type CreateDuplicateSocketResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateDuplicateSocketResponse) Reset() { + *x = CreateDuplicateSocketResponse{} + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateDuplicateSocketResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateDuplicateSocketResponse) ProtoMessage() {} + +func (x *CreateDuplicateSocketResponse) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateDuplicateSocketResponse.ProtoReflect.Descriptor instead. +func (*CreateDuplicateSocketResponse) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_rawDescGZIP(), []int{11} +} + +var File_github_com_Microsoft_hcsshim_pkg_migration_migration_proto protoreflect.FileDescriptor + +const file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_rawDesc = "" + + "\n" + + ":github.com/Microsoft/hcsshim/pkg/migration/migration.proto\x1a\x19google/protobuf/any.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1aBgithub.com/Microsoft/hcsshim/pkg/migration/migration_options.proto\"\x7f\n" + + "\x1ePrepareAndExportSandboxRequest\x12\x1d\n" + + "\n" + + "session_id\x18\x01 \x01(\tR\tsessionId\x12>\n" + + "\finit_options\x18\x02 \x01(\v2\x1b.MigrationInitializeOptionsR\vinitOptions\"O\n" + + "\x1fPrepareAndExportSandboxResponse\x12,\n" + + "\x06config\x18\x01 \x01(\v2\x14.google.protobuf.AnyR\x06config\"c\n" + + "\x14ImportSandboxRequest\x12\x1d\n" + + "\n" + + "session_id\x18\x01 \x01(\tR\tsessionId\x12,\n" + + "\x06config\x18\x02 \x01(\v2\x14.google.protobuf.AnyR\x06config\"\x17\n" + + "\x15ImportSandboxResponse\"v\n" + + "\x15PrepareSandboxRequest\x12\x1d\n" + + "\n" + + "session_id\x18\x01 \x01(\tR\tsessionId\x12>\n" + + "\finit_options\x18\x02 \x01(\v2\x1b.MigrationInitializeOptionsR\vinitOptions\"\x18\n" + + "\x16PrepareSandboxResponse\"l\n" + + "\x16TransferSandboxRequest\x12\x1d\n" + + "\n" + + "session_id\x18\x01 \x01(\tR\tsessionId\x123\n" + + "\atimeout\x18\x02 \x01(\v2\x19.google.protobuf.DurationR\atimeout\"\xdc\x01\n" + + "\x17TransferSandboxResponse\x12\x1d\n" + + "\n" + + "message_id\x18\x01 \x01(\rR\tmessageId\x12\x14\n" + + "\x05event\x18\x02 \x01(\tR\x05event\x12\x14\n" + + "\x05error\x18\x03 \x01(\tR\x05error\x129\n" + + "\n" + + "start_time\x18\x04 \x01(\v2\x1a.google.protobuf.TimestampR\tstartTime\x12;\n" + + "\vupdate_time\x18\x05 \x01(\v2\x1a.google.protobuf.TimestampR\n" + + "updateTime\"`\n" + + "\x16FinalizeSandboxRequest\x12\x1d\n" + + "\n" + + "session_id\x18\x01 \x01(\tR\tsessionId\x12'\n" + + "\x06action\x18\x02 \x01(\x0e2\x0f.FinalizeActionR\x06action\"\x19\n" + + "\x17FinalizeSandboxResponse\"b\n" + + "\x1cCreateDuplicateSocketRequest\x12\x1d\n" + + "\n" + + "session_id\x18\x01 \x01(\tR\tsessionId\x12#\n" + + "\rprotocol_info\x18\x02 \x01(\fR\fprotocolInfo\"\x1f\n" + + "\x1dCreateDuplicateSocketResponse*g\n" + + "\x0eFinalizeAction\x12\x1f\n" + + "\x1bFINALIZE_ACTION_UNSPECIFIED\x10\x00\x12\x18\n" + + "\x14FINALIZE_ACTION_STOP\x10\x01\x12\x1a\n" + + "\x16FINALIZE_ACTION_RESUME\x10\x022\xd2\x03\n" + + "\tMigration\x12\\\n" + + "\x17PrepareAndExportSandbox\x12\x1f.PrepareAndExportSandboxRequest\x1a .PrepareAndExportSandboxResponse\x12>\n" + + "\rImportSandbox\x12\x15.ImportSandboxRequest\x1a\x16.ImportSandboxResponse\x12A\n" + + "\x0ePrepareSandbox\x12\x16.PrepareSandboxRequest\x1a\x17.PrepareSandboxResponse\x12F\n" + + "\x0fTransferSandbox\x12\x17.TransferSandboxRequest\x1a\x18.TransferSandboxResponse0\x01\x12D\n" + + "\x0fFinalizeSandbox\x12\x17.FinalizeSandboxRequest\x1a\x18.FinalizeSandboxResponse\x12V\n" + + "\x15CreateDuplicateSocket\x12\x1d.CreateDuplicateSocketRequest\x1a\x1e.CreateDuplicateSocketResponseB6Z4github.com/Microsoft/hcsshim/pkg/migration;migrationb\x06proto3" + +var ( + file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_rawDescOnce sync.Once + file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_rawDescData []byte +) + +func file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_rawDescGZIP() []byte { + file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_rawDescOnce.Do(func() { + file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_rawDesc), len(file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_rawDesc))) + }) + return file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_rawDescData +} + +var file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_goTypes = []any{ + (FinalizeAction)(0), // 0: FinalizeAction + (*PrepareAndExportSandboxRequest)(nil), // 1: PrepareAndExportSandboxRequest + (*PrepareAndExportSandboxResponse)(nil), // 2: PrepareAndExportSandboxResponse + (*ImportSandboxRequest)(nil), // 3: ImportSandboxRequest + (*ImportSandboxResponse)(nil), // 4: ImportSandboxResponse + (*PrepareSandboxRequest)(nil), // 5: PrepareSandboxRequest + (*PrepareSandboxResponse)(nil), // 6: PrepareSandboxResponse + (*TransferSandboxRequest)(nil), // 7: TransferSandboxRequest + (*TransferSandboxResponse)(nil), // 8: TransferSandboxResponse + (*FinalizeSandboxRequest)(nil), // 9: FinalizeSandboxRequest + (*FinalizeSandboxResponse)(nil), // 10: FinalizeSandboxResponse + (*CreateDuplicateSocketRequest)(nil), // 11: CreateDuplicateSocketRequest + (*CreateDuplicateSocketResponse)(nil), // 12: CreateDuplicateSocketResponse + (*MigrationInitializeOptions)(nil), // 13: MigrationInitializeOptions + (*anypb.Any)(nil), // 14: google.protobuf.Any + (*durationpb.Duration)(nil), // 15: google.protobuf.Duration + (*timestamppb.Timestamp)(nil), // 16: google.protobuf.Timestamp +} +var file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_depIdxs = []int32{ + 13, // 0: PrepareAndExportSandboxRequest.init_options:type_name -> MigrationInitializeOptions + 14, // 1: PrepareAndExportSandboxResponse.config:type_name -> google.protobuf.Any + 14, // 2: ImportSandboxRequest.config:type_name -> google.protobuf.Any + 13, // 3: PrepareSandboxRequest.init_options:type_name -> MigrationInitializeOptions + 15, // 4: TransferSandboxRequest.timeout:type_name -> google.protobuf.Duration + 16, // 5: TransferSandboxResponse.start_time:type_name -> google.protobuf.Timestamp + 16, // 6: TransferSandboxResponse.update_time:type_name -> google.protobuf.Timestamp + 0, // 7: FinalizeSandboxRequest.action:type_name -> FinalizeAction + 1, // 8: Migration.PrepareAndExportSandbox:input_type -> PrepareAndExportSandboxRequest + 3, // 9: Migration.ImportSandbox:input_type -> ImportSandboxRequest + 5, // 10: Migration.PrepareSandbox:input_type -> PrepareSandboxRequest + 7, // 11: Migration.TransferSandbox:input_type -> TransferSandboxRequest + 9, // 12: Migration.FinalizeSandbox:input_type -> FinalizeSandboxRequest + 11, // 13: Migration.CreateDuplicateSocket:input_type -> CreateDuplicateSocketRequest + 2, // 14: Migration.PrepareAndExportSandbox:output_type -> PrepareAndExportSandboxResponse + 4, // 15: Migration.ImportSandbox:output_type -> ImportSandboxResponse + 6, // 16: Migration.PrepareSandbox:output_type -> PrepareSandboxResponse + 8, // 17: Migration.TransferSandbox:output_type -> TransferSandboxResponse + 10, // 18: Migration.FinalizeSandbox:output_type -> FinalizeSandboxResponse + 12, // 19: Migration.CreateDuplicateSocket:output_type -> CreateDuplicateSocketResponse + 14, // [14:20] is the sub-list for method output_type + 8, // [8:14] is the sub-list for method input_type + 8, // [8:8] is the sub-list for extension type_name + 8, // [8:8] is the sub-list for extension extendee + 0, // [0:8] is the sub-list for field type_name +} + +func init() { file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_init() } +func file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_init() { + if File_github_com_Microsoft_hcsshim_pkg_migration_migration_proto != nil { + return + } + file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_init() + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_rawDesc), len(file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_rawDesc)), + NumEnums: 1, + NumMessages: 12, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_goTypes, + DependencyIndexes: file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_depIdxs, + EnumInfos: file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_enumTypes, + MessageInfos: file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_msgTypes, + }.Build() + File_github_com_Microsoft_hcsshim_pkg_migration_migration_proto = out.File + file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_goTypes = nil + file_github_com_Microsoft_hcsshim_pkg_migration_migration_proto_depIdxs = nil +} diff --git a/pkg/migration/migration.proto b/pkg/migration/migration.proto new file mode 100644 index 0000000000..12b7ef043f --- /dev/null +++ b/pkg/migration/migration.proto @@ -0,0 +1,104 @@ +syntax = "proto3"; + +option go_package = "github.com/Microsoft/hcsshim/pkg/migration;migration"; + +import "google/protobuf/any.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/timestamp.proto"; +import "github.com/Microsoft/hcsshim/pkg/migration/migration_options.proto"; + +service Migration { + // Called on SOURCE. Prepares the sandbox for live migration. + rpc PrepareAndExportSandbox(PrepareAndExportSandboxRequest) returns (PrepareAndExportSandboxResponse); + // Called on DESTINATION. Imports the exported sandbox config produced by + // PrepareAndExportSandbox on the source. + rpc ImportSandbox(ImportSandboxRequest) returns (ImportSandboxResponse); + // Called on DESTINATION. Prepares the destination sandbox for migration. + rpc PrepareSandbox(PrepareSandboxRequest) returns (PrepareSandboxResponse); + // Called on SOURCE AND DESTINATION. Initiates memory transfer, and returns a stream of status updates. + rpc TransferSandbox(TransferSandboxRequest) returns (stream TransferSandboxResponse); + // Called on SOURCE AND DESTINATION. Finalizes live migration and starts or deletes the sandbox. + rpc FinalizeSandbox(FinalizeSandboxRequest) returns (FinalizeSandboxResponse); + // Creates a duplicate socket for the migration transport. + rpc CreateDuplicateSocket(CreateDuplicateSocketRequest) returns (CreateDuplicateSocketResponse); +} + +message PrepareAndExportSandboxRequest { + // Idempotency key for the migration session (stable across retries). + string session_id = 1; + // Options for initializing the live migration on the source. + MigrationInitializeOptions init_options = 2; +} + +message PrepareAndExportSandboxResponse { + // An opaque config that should be set in the CreateSandbox input on the destination. + google.protobuf.Any config = 1; +} + +message ImportSandboxRequest { + // Idempotency key for the migration session (must match the key used on the source). + string session_id = 1; + // Opaque config produced by PrepareAndExportSandbox on the source. Forwarded + // verbatim by the caller; the destination service is responsible for decoding it. + google.protobuf.Any config = 2; +} + +message ImportSandboxResponse {} + +message PrepareSandboxRequest { + // Idempotency key for the migration session (must match the key used on the source). + string session_id = 1; + // Options for initializing the live migration on the destination. + MigrationInitializeOptions init_options = 2; +} + +message PrepareSandboxResponse {} + +message TransferSandboxRequest { + // Idempotency key for migration session. + string session_id = 1; + // Max time to wait for socket/connection readiness before declaring TIMEOUT. + // If unset, server uses a sensible default (e.g., 10 minutes). + google.protobuf.Duration timeout = 2; +} + +message TransferSandboxResponse { + // Increments per message; can be used to dedupe after client restarts. + uint32 message_id = 1; + // Event-specific message from the migration notification. + string event = 2; + // Populated when event indicates an error or timeout. + string error = 3; + // When the transfer started (according to the server). + google.protobuf.Timestamp start_time = 4; + // When this update was produced. + google.protobuf.Timestamp update_time = 5; +} + +message FinalizeSandboxRequest { + // Idempotency key for the session (must match the key used in PrepareSandbox). + string session_id = 1; + // Action to perform on the sandbox at finalize time. + FinalizeAction action = 2; +} + +// FinalizeAction specifies the action to take on the sandbox during finalization. +enum FinalizeAction { + // No action specified; the server should treat this as an error or use a default. + FINALIZE_ACTION_UNSPECIFIED = 0; + // Stop and clean up the sandbox. + FINALIZE_ACTION_STOP = 1; + // Resume the sandbox (used on the destination to start running, or on the source to rollback). + FINALIZE_ACTION_RESUME = 2; +} + +message FinalizeSandboxResponse {} + +message CreateDuplicateSocketRequest { + // Idempotency key; must match active LM session. + string session_id = 1; + // Serialized WSAProtocolInfo struct (opaque to clients). + bytes protocol_info = 2; +} + +message CreateDuplicateSocketResponse {} diff --git a/pkg/migration/migration_options.pb.go b/pkg/migration/migration_options.pb.go new file mode 100644 index 0000000000..5f2116ff9a --- /dev/null +++ b/pkg/migration/migration_options.pb.go @@ -0,0 +1,482 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc v5.26.0 +// source: github.com/Microsoft/hcsshim/pkg/migration/migration_options.proto + +package migration + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// MigrationMemoryTransport is the transport protocol used for memory transfer during migration. +type MigrationMemoryTransport int32 + +const ( + MigrationMemoryTransport_MIGRATION_MEMORY_TRANSPORT_UNSPECIFIED MigrationMemoryTransport = 0 + // VM memory is copied over a TCP/IP connection. + MigrationMemoryTransport_MIGRATION_MEMORY_TRANSPORT_TCP MigrationMemoryTransport = 1 +) + +// Enum value maps for MigrationMemoryTransport. +var ( + MigrationMemoryTransport_name = map[int32]string{ + 0: "MIGRATION_MEMORY_TRANSPORT_UNSPECIFIED", + 1: "MIGRATION_MEMORY_TRANSPORT_TCP", + } + MigrationMemoryTransport_value = map[string]int32{ + "MIGRATION_MEMORY_TRANSPORT_UNSPECIFIED": 0, + "MIGRATION_MEMORY_TRANSPORT_TCP": 1, + } +) + +func (x MigrationMemoryTransport) Enum() *MigrationMemoryTransport { + p := new(MigrationMemoryTransport) + *p = x + return p +} + +func (x MigrationMemoryTransport) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (MigrationMemoryTransport) Descriptor() protoreflect.EnumDescriptor { + return file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_enumTypes[0].Descriptor() +} + +func (MigrationMemoryTransport) Type() protoreflect.EnumType { + return &file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_enumTypes[0] +} + +func (x MigrationMemoryTransport) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use MigrationMemoryTransport.Descriptor instead. +func (MigrationMemoryTransport) EnumDescriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_rawDescGZIP(), []int{0} +} + +type MigrationInitializeOptions struct { + state protoimpl.MessageState `protogen:"open.v1"` + // MemoryTransport specifies the transport protocol for memory transfer during migration. + MemoryTransport MigrationMemoryTransport `protobuf:"varint,1,opt,name=memory_transport,json=memoryTransport,proto3,enum=MigrationMemoryTransport" json:"memory_transport,omitempty"` + // MemoryTransferThrottleParams specifies settings for throttling during memory transfer. + MemoryTransferThrottleParams *MemoryMigrationTransferThrottleParams `protobuf:"bytes,2,opt,name=memory_transfer_throttle_params,json=memoryTransferThrottleParams,proto3,oneof" json:"memory_transfer_throttle_params,omitempty"` + // CompressionSettings specifies additional settings when compression is enabled. + CompressionSettings *MigrationCompressionSettings `protobuf:"bytes,3,opt,name=compression_settings,json=compressionSettings,proto3,oneof" json:"compression_settings,omitempty"` + // ChecksumVerification enables memory checksum verification. + ChecksumVerification bool `protobuf:"varint,4,opt,name=checksum_verification,json=checksumVerification,proto3" json:"checksum_verification,omitempty"` + // PerfTracingEnabled enables performance tracing during migration. + PerfTracingEnabled bool `protobuf:"varint,5,opt,name=perf_tracing_enabled,json=perfTracingEnabled,proto3" json:"perf_tracing_enabled,omitempty"` + // CancelIfBlackoutThresholdExceeds cancels the operation if the blackout threshold is exceeded. + CancelIfBlackoutThresholdExceeds bool `protobuf:"varint,6,opt,name=cancel_if_blackout_threshold_exceeds,json=cancelIfBlackoutThresholdExceeds,proto3" json:"cancel_if_blackout_threshold_exceeds,omitempty"` + // PrepareMemoryTransferMode extends timeout for cross-version live migration. + PrepareMemoryTransferMode bool `protobuf:"varint,7,opt,name=prepare_memory_transfer_mode,json=prepareMemoryTransferMode,proto3" json:"prepare_memory_transfer_mode,omitempty"` + // CompatibilityData is the compatibility information required for the destination VM. + CompatibilityData *CompatibilityInfo `protobuf:"bytes,8,opt,name=compatibility_data,json=compatibilityData,proto3,oneof" json:"compatibility_data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *MigrationInitializeOptions) Reset() { + *x = MigrationInitializeOptions{} + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MigrationInitializeOptions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MigrationInitializeOptions) ProtoMessage() {} + +func (x *MigrationInitializeOptions) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MigrationInitializeOptions.ProtoReflect.Descriptor instead. +func (*MigrationInitializeOptions) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_rawDescGZIP(), []int{0} +} + +func (x *MigrationInitializeOptions) GetMemoryTransport() MigrationMemoryTransport { + if x != nil { + return x.MemoryTransport + } + return MigrationMemoryTransport_MIGRATION_MEMORY_TRANSPORT_UNSPECIFIED +} + +func (x *MigrationInitializeOptions) GetMemoryTransferThrottleParams() *MemoryMigrationTransferThrottleParams { + if x != nil { + return x.MemoryTransferThrottleParams + } + return nil +} + +func (x *MigrationInitializeOptions) GetCompressionSettings() *MigrationCompressionSettings { + if x != nil { + return x.CompressionSettings + } + return nil +} + +func (x *MigrationInitializeOptions) GetChecksumVerification() bool { + if x != nil { + return x.ChecksumVerification + } + return false +} + +func (x *MigrationInitializeOptions) GetPerfTracingEnabled() bool { + if x != nil { + return x.PerfTracingEnabled + } + return false +} + +func (x *MigrationInitializeOptions) GetCancelIfBlackoutThresholdExceeds() bool { + if x != nil { + return x.CancelIfBlackoutThresholdExceeds + } + return false +} + +func (x *MigrationInitializeOptions) GetPrepareMemoryTransferMode() bool { + if x != nil { + return x.PrepareMemoryTransferMode + } + return false +} + +func (x *MigrationInitializeOptions) GetCompatibilityData() *CompatibilityInfo { + if x != nil { + return x.CompatibilityData + } + return nil +} + +// CompatibilityInfo is opaque VM compatibility data, primarily used in migration. +type CompatibilityInfo struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Raw compatibility information. + Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CompatibilityInfo) Reset() { + *x = CompatibilityInfo{} + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CompatibilityInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CompatibilityInfo) ProtoMessage() {} + +func (x *CompatibilityInfo) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CompatibilityInfo.ProtoReflect.Descriptor instead. +func (*CompatibilityInfo) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_rawDescGZIP(), []int{1} +} + +func (x *CompatibilityInfo) GetData() []byte { + if x != nil { + return x.Data + } + return nil +} + +type MemoryMigrationTransferThrottleParams struct { + state protoimpl.MessageState `protogen:"open.v1"` + // A flag indicating if throttling should be skipped. + SkipThrottling *bool `protobuf:"varint,1,opt,name=skip_throttling,json=skipThrottling,proto3,oneof" json:"skip_throttling,omitempty"` + // The scale of the throttling. The value is in percentage (1-100). + ThrottlingScale *float64 `protobuf:"fixed64,2,opt,name=throttling_scale,json=throttlingScale,proto3,oneof" json:"throttling_scale,omitempty"` + // Minimum percentage value to which memory transfer can be throttled. + MinimumThrottlePercentage *uint32 `protobuf:"varint,3,opt,name=minimum_throttle_percentage,json=minimumThrottlePercentage,proto3,oneof" json:"minimum_throttle_percentage,omitempty"` + // Number of memory transfer passes targeted before the VM enters blackout. + TargetNumberOfBrownoutTransferPasses *uint32 `protobuf:"varint,4,opt,name=target_number_of_brownout_transfer_passes,json=targetNumberOfBrownoutTransferPasses,proto3,oneof" json:"target_number_of_brownout_transfer_passes,omitempty"` + // The starting transfer pass where throttling is starting. + StartingBrownoutPassNumberForThrottling *uint32 `protobuf:"varint,5,opt,name=starting_brownout_pass_number_for_throttling,json=startingBrownoutPassNumberForThrottling,proto3,oneof" json:"starting_brownout_pass_number_for_throttling,omitempty"` + // Maximum number of memory transfer passes before forcing the VM to enter blackout. + MaximumNumberOfBrownoutTransferPasses *uint32 `protobuf:"varint,6,opt,name=maximum_number_of_brownout_transfer_passes,json=maximumNumberOfBrownoutTransferPasses,proto3,oneof" json:"maximum_number_of_brownout_transfer_passes,omitempty"` + // Expected duration for blackout transfer time. + TargetBlackoutTransferTime *uint32 `protobuf:"varint,7,opt,name=target_blackout_transfer_time,json=targetBlackoutTransferTime,proto3,oneof" json:"target_blackout_transfer_time,omitempty"` + // Threshold for blackout duration prior to cancelling migration. + BlackoutTimeThresholdForCancellingMigration *uint32 `protobuf:"varint,8,opt,name=blackout_time_threshold_for_cancelling_migration,json=blackoutTimeThresholdForCancellingMigration,proto3,oneof" json:"blackout_time_threshold_for_cancelling_migration,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *MemoryMigrationTransferThrottleParams) Reset() { + *x = MemoryMigrationTransferThrottleParams{} + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MemoryMigrationTransferThrottleParams) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MemoryMigrationTransferThrottleParams) ProtoMessage() {} + +func (x *MemoryMigrationTransferThrottleParams) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MemoryMigrationTransferThrottleParams.ProtoReflect.Descriptor instead. +func (*MemoryMigrationTransferThrottleParams) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_rawDescGZIP(), []int{2} +} + +func (x *MemoryMigrationTransferThrottleParams) GetSkipThrottling() bool { + if x != nil && x.SkipThrottling != nil { + return *x.SkipThrottling + } + return false +} + +func (x *MemoryMigrationTransferThrottleParams) GetThrottlingScale() float64 { + if x != nil && x.ThrottlingScale != nil { + return *x.ThrottlingScale + } + return 0 +} + +func (x *MemoryMigrationTransferThrottleParams) GetMinimumThrottlePercentage() uint32 { + if x != nil && x.MinimumThrottlePercentage != nil { + return *x.MinimumThrottlePercentage + } + return 0 +} + +func (x *MemoryMigrationTransferThrottleParams) GetTargetNumberOfBrownoutTransferPasses() uint32 { + if x != nil && x.TargetNumberOfBrownoutTransferPasses != nil { + return *x.TargetNumberOfBrownoutTransferPasses + } + return 0 +} + +func (x *MemoryMigrationTransferThrottleParams) GetStartingBrownoutPassNumberForThrottling() uint32 { + if x != nil && x.StartingBrownoutPassNumberForThrottling != nil { + return *x.StartingBrownoutPassNumberForThrottling + } + return 0 +} + +func (x *MemoryMigrationTransferThrottleParams) GetMaximumNumberOfBrownoutTransferPasses() uint32 { + if x != nil && x.MaximumNumberOfBrownoutTransferPasses != nil { + return *x.MaximumNumberOfBrownoutTransferPasses + } + return 0 +} + +func (x *MemoryMigrationTransferThrottleParams) GetTargetBlackoutTransferTime() uint32 { + if x != nil && x.TargetBlackoutTransferTime != nil { + return *x.TargetBlackoutTransferTime + } + return 0 +} + +func (x *MemoryMigrationTransferThrottleParams) GetBlackoutTimeThresholdForCancellingMigration() uint32 { + if x != nil && x.BlackoutTimeThresholdForCancellingMigration != nil { + return *x.BlackoutTimeThresholdForCancellingMigration + } + return 0 +} + +type MigrationCompressionSettings struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Number of worker threads used for [de]compression. Values higher than what the host + // and VM configuration can support will be adjusted. The value should be non-zero. + ThrottleWorkerCount *uint32 `protobuf:"varint,1,opt,name=throttle_worker_count,json=throttleWorkerCount,proto3,oneof" json:"throttle_worker_count,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *MigrationCompressionSettings) Reset() { + *x = MigrationCompressionSettings{} + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MigrationCompressionSettings) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MigrationCompressionSettings) ProtoMessage() {} + +func (x *MigrationCompressionSettings) ProtoReflect() protoreflect.Message { + mi := &file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MigrationCompressionSettings.ProtoReflect.Descriptor instead. +func (*MigrationCompressionSettings) Descriptor() ([]byte, []int) { + return file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_rawDescGZIP(), []int{3} +} + +func (x *MigrationCompressionSettings) GetThrottleWorkerCount() uint32 { + if x != nil && x.ThrottleWorkerCount != nil { + return *x.ThrottleWorkerCount + } + return 0 +} + +var File_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto protoreflect.FileDescriptor + +const file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_rawDesc = "" + + "\n" + + "Bgithub.com/Microsoft/hcsshim/pkg/migration/migration_options.proto\"\xc1\x05\n" + + "\x1aMigrationInitializeOptions\x12D\n" + + "\x10memory_transport\x18\x01 \x01(\x0e2\x19.MigrationMemoryTransportR\x0fmemoryTransport\x12r\n" + + "\x1fmemory_transfer_throttle_params\x18\x02 \x01(\v2&.MemoryMigrationTransferThrottleParamsH\x00R\x1cmemoryTransferThrottleParams\x88\x01\x01\x12U\n" + + "\x14compression_settings\x18\x03 \x01(\v2\x1d.MigrationCompressionSettingsH\x01R\x13compressionSettings\x88\x01\x01\x123\n" + + "\x15checksum_verification\x18\x04 \x01(\bR\x14checksumVerification\x120\n" + + "\x14perf_tracing_enabled\x18\x05 \x01(\bR\x12perfTracingEnabled\x12N\n" + + "$cancel_if_blackout_threshold_exceeds\x18\x06 \x01(\bR cancelIfBlackoutThresholdExceeds\x12?\n" + + "\x1cprepare_memory_transfer_mode\x18\a \x01(\bR\x19prepareMemoryTransferMode\x12F\n" + + "\x12compatibility_data\x18\b \x01(\v2\x12.CompatibilityInfoH\x02R\x11compatibilityData\x88\x01\x01B\"\n" + + " _memory_transfer_throttle_paramsB\x17\n" + + "\x15_compression_settingsB\x15\n" + + "\x13_compatibility_data\"'\n" + + "\x11CompatibilityInfo\x12\x12\n" + + "\x04data\x18\x01 \x01(\fR\x04data\"\xce\a\n" + + "%MemoryMigrationTransferThrottleParams\x12,\n" + + "\x0fskip_throttling\x18\x01 \x01(\bH\x00R\x0eskipThrottling\x88\x01\x01\x12.\n" + + "\x10throttling_scale\x18\x02 \x01(\x01H\x01R\x0fthrottlingScale\x88\x01\x01\x12C\n" + + "\x1bminimum_throttle_percentage\x18\x03 \x01(\rH\x02R\x19minimumThrottlePercentage\x88\x01\x01\x12\\\n" + + ")target_number_of_brownout_transfer_passes\x18\x04 \x01(\rH\x03R$targetNumberOfBrownoutTransferPasses\x88\x01\x01\x12b\n" + + ",starting_brownout_pass_number_for_throttling\x18\x05 \x01(\rH\x04R'startingBrownoutPassNumberForThrottling\x88\x01\x01\x12^\n" + + "*maximum_number_of_brownout_transfer_passes\x18\x06 \x01(\rH\x05R%maximumNumberOfBrownoutTransferPasses\x88\x01\x01\x12F\n" + + "\x1dtarget_blackout_transfer_time\x18\a \x01(\rH\x06R\x1atargetBlackoutTransferTime\x88\x01\x01\x12j\n" + + "0blackout_time_threshold_for_cancelling_migration\x18\b \x01(\rH\aR+blackoutTimeThresholdForCancellingMigration\x88\x01\x01B\x12\n" + + "\x10_skip_throttlingB\x13\n" + + "\x11_throttling_scaleB\x1e\n" + + "\x1c_minimum_throttle_percentageB,\n" + + "*_target_number_of_brownout_transfer_passesB/\n" + + "-_starting_brownout_pass_number_for_throttlingB-\n" + + "+_maximum_number_of_brownout_transfer_passesB \n" + + "\x1e_target_blackout_transfer_timeB3\n" + + "1_blackout_time_threshold_for_cancelling_migration\"q\n" + + "\x1cMigrationCompressionSettings\x127\n" + + "\x15throttle_worker_count\x18\x01 \x01(\rH\x00R\x13throttleWorkerCount\x88\x01\x01B\x18\n" + + "\x16_throttle_worker_count*j\n" + + "\x18MigrationMemoryTransport\x12*\n" + + "&MIGRATION_MEMORY_TRANSPORT_UNSPECIFIED\x10\x00\x12\"\n" + + "\x1eMIGRATION_MEMORY_TRANSPORT_TCP\x10\x01B6Z4github.com/Microsoft/hcsshim/pkg/migration;migrationb\x06proto3" + +var ( + file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_rawDescOnce sync.Once + file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_rawDescData []byte +) + +func file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_rawDescGZIP() []byte { + file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_rawDescOnce.Do(func() { + file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_rawDesc), len(file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_rawDesc))) + }) + return file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_rawDescData +} + +var file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_goTypes = []any{ + (MigrationMemoryTransport)(0), // 0: MigrationMemoryTransport + (*MigrationInitializeOptions)(nil), // 1: MigrationInitializeOptions + (*CompatibilityInfo)(nil), // 2: CompatibilityInfo + (*MemoryMigrationTransferThrottleParams)(nil), // 3: MemoryMigrationTransferThrottleParams + (*MigrationCompressionSettings)(nil), // 4: MigrationCompressionSettings +} +var file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_depIdxs = []int32{ + 0, // 0: MigrationInitializeOptions.memory_transport:type_name -> MigrationMemoryTransport + 3, // 1: MigrationInitializeOptions.memory_transfer_throttle_params:type_name -> MemoryMigrationTransferThrottleParams + 4, // 2: MigrationInitializeOptions.compression_settings:type_name -> MigrationCompressionSettings + 2, // 3: MigrationInitializeOptions.compatibility_data:type_name -> CompatibilityInfo + 4, // [4:4] is the sub-list for method output_type + 4, // [4:4] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name +} + +func init() { file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_init() } +func file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_init() { + if File_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto != nil { + return + } + file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_msgTypes[0].OneofWrappers = []any{} + file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_msgTypes[2].OneofWrappers = []any{} + file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_msgTypes[3].OneofWrappers = []any{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_rawDesc), len(file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_rawDesc)), + NumEnums: 1, + NumMessages: 4, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_goTypes, + DependencyIndexes: file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_depIdxs, + EnumInfos: file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_enumTypes, + MessageInfos: file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_msgTypes, + }.Build() + File_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto = out.File + file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_goTypes = nil + file_github_com_Microsoft_hcsshim_pkg_migration_migration_options_proto_depIdxs = nil +} diff --git a/pkg/migration/migration_options.proto b/pkg/migration/migration_options.proto new file mode 100644 index 0000000000..e7ad0b75ad --- /dev/null +++ b/pkg/migration/migration_options.proto @@ -0,0 +1,60 @@ +syntax = "proto3"; + +option go_package = "github.com/Microsoft/hcsshim/pkg/migration;migration"; + +// MigrationMemoryTransport is the transport protocol used for memory transfer during migration. +enum MigrationMemoryTransport { + MIGRATION_MEMORY_TRANSPORT_UNSPECIFIED = 0; + // VM memory is copied over a TCP/IP connection. + MIGRATION_MEMORY_TRANSPORT_TCP = 1; +} + +message MigrationInitializeOptions { + // MemoryTransport specifies the transport protocol for memory transfer during migration. + MigrationMemoryTransport memory_transport = 1; + // MemoryTransferThrottleParams specifies settings for throttling during memory transfer. + optional MemoryMigrationTransferThrottleParams memory_transfer_throttle_params = 2; + // CompressionSettings specifies additional settings when compression is enabled. + optional MigrationCompressionSettings compression_settings = 3; + // ChecksumVerification enables memory checksum verification. + bool checksum_verification = 4; + // PerfTracingEnabled enables performance tracing during migration. + bool perf_tracing_enabled = 5; + // CancelIfBlackoutThresholdExceeds cancels the operation if the blackout threshold is exceeded. + bool cancel_if_blackout_threshold_exceeds = 6; + // PrepareMemoryTransferMode extends timeout for cross-version live migration. + bool prepare_memory_transfer_mode = 7; + // CompatibilityData is the compatibility information required for the destination VM. + optional CompatibilityInfo compatibility_data = 8; +} + +// CompatibilityInfo is opaque VM compatibility data, primarily used in migration. +message CompatibilityInfo { + // Raw compatibility information. + bytes data = 1; +} + +message MemoryMigrationTransferThrottleParams { + // A flag indicating if throttling should be skipped. + optional bool skip_throttling = 1; + // The scale of the throttling. The value is in percentage (1-100). + optional double throttling_scale = 2; + // Minimum percentage value to which memory transfer can be throttled. + optional uint32 minimum_throttle_percentage = 3; + // Number of memory transfer passes targeted before the VM enters blackout. + optional uint32 target_number_of_brownout_transfer_passes = 4; + // The starting transfer pass where throttling is starting. + optional uint32 starting_brownout_pass_number_for_throttling = 5; + // Maximum number of memory transfer passes before forcing the VM to enter blackout. + optional uint32 maximum_number_of_brownout_transfer_passes = 6; + // Expected duration for blackout transfer time. + optional uint32 target_blackout_transfer_time = 7; + // Threshold for blackout duration prior to cancelling migration. + optional uint32 blackout_time_threshold_for_cancelling_migration = 8; +} + +message MigrationCompressionSettings { + // Number of worker threads used for [de]compression. Values higher than what the host + // and VM configuration can support will be adjusted. The value should be non-zero. + optional uint32 throttle_worker_count = 1; +} diff --git a/pkg/migration/migration_ttrpc.pb.go b/pkg/migration/migration_ttrpc.pb.go new file mode 100644 index 0000000000..63f6404b31 --- /dev/null +++ b/pkg/migration/migration_ttrpc.pb.go @@ -0,0 +1,173 @@ +// Code generated by protoc-gen-go-ttrpc. DO NOT EDIT. +// source: github.com/Microsoft/hcsshim/pkg/migration/migration.proto +package migration + +import ( + context "context" + ttrpc "github.com/containerd/ttrpc" +) + +type MigrationService interface { + PrepareAndExportSandbox(context.Context, *PrepareAndExportSandboxRequest) (*PrepareAndExportSandboxResponse, error) + ImportSandbox(context.Context, *ImportSandboxRequest) (*ImportSandboxResponse, error) + PrepareSandbox(context.Context, *PrepareSandboxRequest) (*PrepareSandboxResponse, error) + TransferSandbox(context.Context, *TransferSandboxRequest, Migration_TransferSandboxServer) error + FinalizeSandbox(context.Context, *FinalizeSandboxRequest) (*FinalizeSandboxResponse, error) + CreateDuplicateSocket(context.Context, *CreateDuplicateSocketRequest) (*CreateDuplicateSocketResponse, error) +} + +type Migration_TransferSandboxServer interface { + Send(*TransferSandboxResponse) error + ttrpc.StreamServer +} + +type migrationTransferSandboxServer struct { + ttrpc.StreamServer +} + +func (x *migrationTransferSandboxServer) Send(m *TransferSandboxResponse) error { + return x.StreamServer.SendMsg(m) +} + +func RegisterMigrationService(srv *ttrpc.Server, svc MigrationService) { + srv.RegisterService("Migration", &ttrpc.ServiceDesc{ + Methods: map[string]ttrpc.Method{ + "PrepareAndExportSandbox": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req PrepareAndExportSandboxRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.PrepareAndExportSandbox(ctx, &req) + }, + "ImportSandbox": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req ImportSandboxRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.ImportSandbox(ctx, &req) + }, + "PrepareSandbox": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req PrepareSandboxRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.PrepareSandbox(ctx, &req) + }, + "FinalizeSandbox": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req FinalizeSandboxRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.FinalizeSandbox(ctx, &req) + }, + "CreateDuplicateSocket": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req CreateDuplicateSocketRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.CreateDuplicateSocket(ctx, &req) + }, + }, + Streams: map[string]ttrpc.Stream{ + "TransferSandbox": { + Handler: func(ctx context.Context, stream ttrpc.StreamServer) (interface{}, error) { + m := new(TransferSandboxRequest) + if err := stream.RecvMsg(m); err != nil { + return nil, err + } + return nil, svc.TransferSandbox(ctx, m, &migrationTransferSandboxServer{stream}) + }, + StreamingClient: false, + StreamingServer: true, + }, + }, + }) +} + +type MigrationClient interface { + PrepareAndExportSandbox(context.Context, *PrepareAndExportSandboxRequest) (*PrepareAndExportSandboxResponse, error) + ImportSandbox(context.Context, *ImportSandboxRequest) (*ImportSandboxResponse, error) + PrepareSandbox(context.Context, *PrepareSandboxRequest) (*PrepareSandboxResponse, error) + TransferSandbox(context.Context, *TransferSandboxRequest) (Migration_TransferSandboxClient, error) + FinalizeSandbox(context.Context, *FinalizeSandboxRequest) (*FinalizeSandboxResponse, error) + CreateDuplicateSocket(context.Context, *CreateDuplicateSocketRequest) (*CreateDuplicateSocketResponse, error) +} + +type migrationClient struct { + client *ttrpc.Client +} + +func NewMigrationClient(client *ttrpc.Client) MigrationClient { + return &migrationClient{ + client: client, + } +} + +func (c *migrationClient) PrepareAndExportSandbox(ctx context.Context, req *PrepareAndExportSandboxRequest) (*PrepareAndExportSandboxResponse, error) { + var resp PrepareAndExportSandboxResponse + if err := c.client.Call(ctx, "Migration", "PrepareAndExportSandbox", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *migrationClient) ImportSandbox(ctx context.Context, req *ImportSandboxRequest) (*ImportSandboxResponse, error) { + var resp ImportSandboxResponse + if err := c.client.Call(ctx, "Migration", "ImportSandbox", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *migrationClient) PrepareSandbox(ctx context.Context, req *PrepareSandboxRequest) (*PrepareSandboxResponse, error) { + var resp PrepareSandboxResponse + if err := c.client.Call(ctx, "Migration", "PrepareSandbox", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *migrationClient) TransferSandbox(ctx context.Context, req *TransferSandboxRequest) (Migration_TransferSandboxClient, error) { + stream, err := c.client.NewStream(ctx, &ttrpc.StreamDesc{ + StreamingClient: false, + StreamingServer: true, + }, "Migration", "TransferSandbox", req) + if err != nil { + return nil, err + } + x := &migrationTransferSandboxClient{stream} + return x, nil +} + +type Migration_TransferSandboxClient interface { + Recv() (*TransferSandboxResponse, error) + ttrpc.ClientStream +} + +type migrationTransferSandboxClient struct { + ttrpc.ClientStream +} + +func (x *migrationTransferSandboxClient) Recv() (*TransferSandboxResponse, error) { + m := new(TransferSandboxResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *migrationClient) FinalizeSandbox(ctx context.Context, req *FinalizeSandboxRequest) (*FinalizeSandboxResponse, error) { + var resp FinalizeSandboxResponse + if err := c.client.Call(ctx, "Migration", "FinalizeSandbox", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func (c *migrationClient) CreateDuplicateSocket(ctx context.Context, req *CreateDuplicateSocketRequest) (*CreateDuplicateSocketResponse, error) { + var resp CreateDuplicateSocketResponse + if err := c.client.Call(ctx, "Migration", "CreateDuplicateSocket", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} From 0e15ae61b9045c40ca8cd8ab197f9412d19361d2 Mon Sep 17 00:00:00 2001 From: Harsh Rawat Date: Tue, 21 Apr 2026 00:37:34 +0530 Subject: [PATCH 2/3] review 2 Signed-off-by: Harsh Rawat --- pkg/migration/migration.pb.go | 81 ++++++++++----- pkg/migration/migration.proto | 182 ++++++++++++++++++++++++++++------ 2 files changed, 208 insertions(+), 55 deletions(-) diff --git a/pkg/migration/migration.pb.go b/pkg/migration/migration.pb.go index 05592f06eb..0513d2cac4 100644 --- a/pkg/migration/migration.pb.go +++ b/pkg/migration/migration.pb.go @@ -24,15 +24,24 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// FinalizeAction specifies the action to take on the sandbox during finalization. +// FinalizeAction specifies the action to take on the sandbox during +// finalization. The concrete meaning depends on whether the call is made +// on the source or the destination — see the FinalizeSandbox RPC docs. type FinalizeAction int32 const ( - // No action specified; the server should treat this as an error or use a default. + // No action specified. Servers should treat this as an error rather + // than silently picking a default, since the wrong choice can either + // destroy a running VM or leak a stopped one. FinalizeAction_FINALIZE_ACTION_UNSPECIFIED FinalizeAction = 0 - // Stop and clean up the sandbox. + // Stop and clean up the sandbox on this side. On the source this is + // used after a successful migration; on the destination this is used + // when the migration was cancelled or failed. FinalizeAction_FINALIZE_ACTION_STOP FinalizeAction = 1 - // Resume the sandbox (used on the destination to start running, or on the source to rollback). + // Resume the sandbox on this side. On the destination this completes + // a successful migration by bringing the migrated VM back to a + // running state; on the source this is used to roll back when the + // migration was cancelled or failed. FinalizeAction_FINALIZE_ACTION_RESUME FinalizeAction = 2 ) @@ -79,9 +88,13 @@ func (FinalizeAction) EnumDescriptor() ([]byte, []int) { type PrepareAndExportSandboxRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - // Idempotency key for the migration session (stable across retries). + // Identifier for the migration session. The same session_id is used on + // both source and destination for the lifetime of this LM and is what + // ties subsequent calls (TransferSandbox, FinalizeSandbox, etc.) back + // to this sandbox. SessionID string `protobuf:"bytes,1,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` - // Options for initializing the live migration on the source. + // Source-side options that control how live migration is initialized + // on the compute system. InitOptions *MigrationInitializeOptions `protobuf:"bytes,2,opt,name=init_options,json=initOptions,proto3" json:"init_options,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -133,7 +146,10 @@ func (x *PrepareAndExportSandboxRequest) GetInitOptions() *MigrationInitializeOp type PrepareAndExportSandboxResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - // An opaque config that should be set in the CreateSandbox input on the destination. + // Opaque, serialized snapshot of the source shim's view of the sandbox + // and its containers. The caller must forward this verbatim as the + // `config` field of ImportSandboxRequest on the destination; only the + // destination shim knows how to decode it. Config *anypb.Any `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -178,10 +194,12 @@ func (x *PrepareAndExportSandboxResponse) GetConfig() *anypb.Any { type ImportSandboxRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - // Idempotency key for the migration session (must match the key used on the source). + // Identifier for the migration session. Must match the session_id used + // on the source for this LM. SessionID string `protobuf:"bytes,1,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` - // Opaque config produced by PrepareAndExportSandbox on the source. Forwarded - // verbatim by the caller; the destination service is responsible for decoding it. + // Opaque config produced by PrepareAndExportSandbox on the source. + // Forwarded verbatim by the caller; the destination shim is responsible + // for decoding and applying it. Config *anypb.Any `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -269,9 +287,11 @@ func (*ImportSandboxResponse) Descriptor() ([]byte, []int) { type PrepareSandboxRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - // Idempotency key for the migration session (must match the key used on the source). + // Identifier for the migration session. Must match the session_id used + // by ImportSandbox on this destination. SessionID string `protobuf:"bytes,1,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` - // Options for initializing the live migration on the destination. + // Destination-side options that control how live migration is + // initialized when the HCS compute system is created. InitOptions *MigrationInitializeOptions `protobuf:"bytes,2,opt,name=init_options,json=initOptions,proto3" json:"init_options,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -359,10 +379,13 @@ func (*PrepareSandboxResponse) Descriptor() ([]byte, []int) { type TransferSandboxRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - // Idempotency key for migration session. + // Identifier for the migration session. Must match the session_id used + // for the rest of this LM on this side. SessionID string `protobuf:"bytes,1,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` - // Max time to wait for socket/connection readiness before declaring TIMEOUT. - // If unset, server uses a sensible default (e.g., 10 minutes). + // Maximum time to wait for the migration socket / underlying transport + // to become ready before the server gives up and reports a TIMEOUT + // event on the response stream. If unset, the server applies a sensible + // default (e.g. 10 minutes). Timeout *durationpb.Duration `protobuf:"bytes,2,opt,name=timeout,proto3" json:"timeout,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -414,15 +437,18 @@ func (x *TransferSandboxRequest) GetTimeout() *durationpb.Duration { type TransferSandboxResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - // Increments per message; can be used to dedupe after client restarts. + // Monotonically increasing per-message counter on this stream. Useful + // for de-duplication if the client reconnects mid-transfer. MessageID uint32 `protobuf:"varint,1,opt,name=message_id,json=messageId,proto3" json:"message_id,omitempty"` - // Event-specific message from the migration notification. + // Event-specific message describing the current migration notification + // (e.g. progress milestone, state change). Event string `protobuf:"bytes,2,opt,name=event,proto3" json:"event,omitempty"` - // Populated when event indicates an error or timeout. + // Populated when `event` indicates an error or a timeout; empty + // otherwise. Error string `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"` - // When the transfer started (according to the server). + // Server-side timestamp of when the transfer began. StartTime *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=start_time,json=startTime,proto3" json:"start_time,omitempty"` - // When this update was produced. + // Server-side timestamp of when this particular update was produced. UpdateTime *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=update_time,json=updateTime,proto3" json:"update_time,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -495,9 +521,12 @@ func (x *TransferSandboxResponse) GetUpdateTime() *timestamppb.Timestamp { type FinalizeSandboxRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - // Idempotency key for the session (must match the key used in PrepareSandbox). + // Identifier for the migration session. Must match the session_id used + // for the rest of this LM on this side. SessionID string `protobuf:"bytes,1,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` - // Action to perform on the sandbox at finalize time. + // Action the shim should take on the sandbox during finalization. See + // FinalizeAction and the FinalizeSandbox RPC documentation for the + // per-side semantics of STOP vs. RESUME. Action FinalizeAction `protobuf:"varint,2,opt,name=action,proto3,enum=FinalizeAction" json:"action,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -585,9 +614,13 @@ func (*FinalizeSandboxResponse) Descriptor() ([]byte, []int) { type CreateDuplicateSocketRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - // Idempotency key; must match active LM session. + // Identifier for the active LM session. Must match the session_id used + // for the rest of this LM on this side. SessionID string `protobuf:"bytes,1,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` - // Serialized WSAProtocolInfo struct (opaque to clients). + // Serialized WSAProtocolInfo struct describing the source socket whose + // handle should be duplicated into the shim process. The exact layout + // is opaque to clients; the shim feeds it directly to WSASocket to + // create the duplicate. ProtocolInfo []byte `protobuf:"bytes,2,opt,name=protocol_info,json=protocolInfo,proto3" json:"protocol_info,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache diff --git a/pkg/migration/migration.proto b/pkg/migration/migration.proto index 12b7ef043f..2296580b88 100644 --- a/pkg/migration/migration.proto +++ b/pkg/migration/migration.proto @@ -7,97 +7,217 @@ import "google/protobuf/duration.proto"; import "google/protobuf/timestamp.proto"; import "github.com/Microsoft/hcsshim/pkg/migration/migration_options.proto"; +// Migration is the ttrpc service exposed by the shim that orchestrates a live +// migration (LM) of a sandbox (utility VM and its containers) from a SOURCE +// host to a DESTINATION host. +// +// High-level flow (in order): +// +// SOURCE DESTINATION +// ------ ----------- +// 1. PrepareAndExportSandbox ─────────► 2. ImportSandbox +// 3. NewTask (per container, repeated) +// 4. PrepareSandbox +// 5. CreateDuplicateSocket 5. CreateDuplicateSocket +// 6. TransferSandbox ◄────────► 6. TransferSandbox +// 7. FinalizeSandbox 7. FinalizeSandbox +// +// NewTask is part of the existing task service (not this service) and is what +// the destination uses to attach updated resource paths to the rehydrated +// shim state produced by ImportSandbox. service Migration { - // Called on SOURCE. Prepares the sandbox for live migration. + // PrepareAndExportSandbox is the FIRST call of a live migration and is + // invoked on the SOURCE shim. + // + // It performs two things: + // 1. Calls into HCS to initialize live migration on the underlying + // compute system. After this returns successfully, the utility VM + // is in the "migrating" state and is no longer mutable. + // 2. Collects the full in-memory state of the source shim (sandbox + // and container bookkeeping) and returns it as an opaque blob to + // the caller. + // + // The caller is expected to forward the returned opaque config verbatim + // to ImportSandbox on the destination. rpc PrepareAndExportSandbox(PrepareAndExportSandboxRequest) returns (PrepareAndExportSandboxResponse); - // Called on DESTINATION. Imports the exported sandbox config produced by - // PrepareAndExportSandbox on the source. + + // ImportSandbox is the FIRST call made on the DESTINATION shim. + // + // It consumes the opaque config produced by PrepareAndExportSandbox on + // the source and rehydrates the destination shim with that state so that + // it mirrors the source's view of the sandbox and its containers. + // + // ImportSandbox does NOT create any HCS compute system, and + // the resource paths embedded in the rehydrated state still refer to + // source-host paths. Those paths must be fixed up by issuing a NewTask + // call (on the existing task service) for each container. Each NewTask + // identifies the corresponding container imported here and supplies the + // updated, destination-local resource paths, which the shim then patches + // into the rehydrated state. rpc ImportSandbox(ImportSandboxRequest) returns (ImportSandboxResponse); - // Called on DESTINATION. Prepares the destination sandbox for migration. + + // PrepareSandbox is the SECOND call made on the DESTINATION shim, after + // ImportSandbox and after a NewTask has been issued for every container + // in the sandbox. + // + // At this point the shim has a complete, destination-correct view of the + // sandbox. PrepareSandbox uses that view to create the HCS compute + // system on the destination with the updated resources. The compute + // system is created but NOT started; starting happens later, as part of + // TransferSandbox. rpc PrepareSandbox(PrepareSandboxRequest) returns (PrepareSandboxResponse); - // Called on SOURCE AND DESTINATION. Initiates memory transfer, and returns a stream of status updates. + + // TransferSandbox drives the actual memory transfer between source and + // destination. It is called on BOTH sides and returns a stream of + // progress / status updates so the caller can observe the transfer. + // + // The stream remains open for the duration of the transfer and emits + // TransferSandboxResponse messages as state changes (progress, error, + // timeout, completion). rpc TransferSandbox(TransferSandboxRequest) returns (stream TransferSandboxResponse); - // Called on SOURCE AND DESTINATION. Finalizes live migration and starts or deletes the sandbox. + + // FinalizeSandbox terminates a live migration session. It is called on + // BOTH the source and the destination, and the meaning of the action + // depends on which side it is being invoked on: + // + // SOURCE: + // - STOP : Migration completed successfully; tear down the source + // compute system and release its resources. + // - RESUME : Migration was cancelled or failed; roll back and + // resume running the VM on the source. + // + // DESTINATION: + // - STOP : Migration was cancelled or failed; discard the + // destination compute system and clean up. + // - RESUME : Migration completed successfully; bring the migrated + // VM back to a running state on the destination. rpc FinalizeSandbox(FinalizeSandboxRequest) returns (FinalizeSandboxResponse); - // Creates a duplicate socket for the migration transport. + + // CreateDuplicateSocket is called on BOTH the source and destination + // shims, after the caller has created the underlying + // migration transport sockets on each host. The caller hands the shim + // an opaque, serialized WSAProtocolInfo describing one of those sockets, + // and the shim uses it to materialize a duplicate handle to that same + // socket inside the shim process. + // + // This must be invoked prior to TransferSandbox on each side, because + // TransferSandbox uses the duplicated socket as the migration channel + // owned by the shim. + // + // Duplicating the sockets into the shim decouples the migration + // transport from the containerd process lifetime: once the duplicates + // exist, the shim alone can drive the migration to completion. This + // also provides resiliency — if containerd is interrupted mid-migration, + // the duplicated sockets in the shim continue to work and the shim can + // finish the live migration on its own. rpc CreateDuplicateSocket(CreateDuplicateSocketRequest) returns (CreateDuplicateSocketResponse); } message PrepareAndExportSandboxRequest { - // Idempotency key for the migration session (stable across retries). + // Identifier for the migration session. The same session_id is used on + // both source and destination for the lifetime of this LM and is what + // ties subsequent calls (TransferSandbox, FinalizeSandbox, etc.) back + // to this sandbox. string session_id = 1; - // Options for initializing the live migration on the source. + // Source-side options that control how live migration is initialized + // on the compute system. MigrationInitializeOptions init_options = 2; } message PrepareAndExportSandboxResponse { - // An opaque config that should be set in the CreateSandbox input on the destination. + // Opaque, serialized snapshot of the source shim's view of the sandbox + // and its containers. The caller must forward this verbatim as the + // `config` field of ImportSandboxRequest on the destination; only the + // destination shim knows how to decode it. google.protobuf.Any config = 1; } message ImportSandboxRequest { - // Idempotency key for the migration session (must match the key used on the source). + // Identifier for the migration session. Must match the session_id used + // on the source for this LM. string session_id = 1; - // Opaque config produced by PrepareAndExportSandbox on the source. Forwarded - // verbatim by the caller; the destination service is responsible for decoding it. + // Opaque config produced by PrepareAndExportSandbox on the source. + // Forwarded verbatim by the caller; the destination shim is responsible + // for decoding and applying it. google.protobuf.Any config = 2; } message ImportSandboxResponse {} message PrepareSandboxRequest { - // Idempotency key for the migration session (must match the key used on the source). + // Identifier for the migration session. Must match the session_id used + // by ImportSandbox on this destination. string session_id = 1; - // Options for initializing the live migration on the destination. + // Destination-side options that control how live migration is + // initialized when the HCS compute system is created. MigrationInitializeOptions init_options = 2; } message PrepareSandboxResponse {} message TransferSandboxRequest { - // Idempotency key for migration session. + // Identifier for the migration session. Must match the session_id used + // for the rest of this LM on this side. string session_id = 1; - // Max time to wait for socket/connection readiness before declaring TIMEOUT. - // If unset, server uses a sensible default (e.g., 10 minutes). + // Maximum time to wait for the migration socket / underlying transport + // to become ready before the server gives up and reports a TIMEOUT + // event on the response stream. If unset, the server applies a sensible + // default (e.g. 10 minutes). google.protobuf.Duration timeout = 2; } message TransferSandboxResponse { - // Increments per message; can be used to dedupe after client restarts. + // Monotonically increasing per-message counter on this stream. Useful + // for de-duplication if the client reconnects mid-transfer. uint32 message_id = 1; - // Event-specific message from the migration notification. + // Event-specific message describing the current migration notification. string event = 2; - // Populated when event indicates an error or timeout. + // Populated when `event` indicates an error or a timeout; empty + // otherwise. string error = 3; - // When the transfer started (according to the server). + // Server-side timestamp of when the transfer began. google.protobuf.Timestamp start_time = 4; - // When this update was produced. + // Server-side timestamp of when this particular update was produced. google.protobuf.Timestamp update_time = 5; } message FinalizeSandboxRequest { - // Idempotency key for the session (must match the key used in PrepareSandbox). + // Identifier for the migration session. Must match the session_id used + // for the rest of this LM on this side. string session_id = 1; - // Action to perform on the sandbox at finalize time. + // Action the shim should take on the sandbox during finalization. See + // FinalizeAction and the FinalizeSandbox RPC documentation for the + // per-side semantics of STOP vs. RESUME. FinalizeAction action = 2; } -// FinalizeAction specifies the action to take on the sandbox during finalization. +// FinalizeAction specifies the action to take on the sandbox during +// finalization. The concrete meaning depends on whether the call is made +// on the source or the destination — see the FinalizeSandbox RPC docs. enum FinalizeAction { - // No action specified; the server should treat this as an error or use a default. + // No action specified. Servers should treat this as an error. FINALIZE_ACTION_UNSPECIFIED = 0; - // Stop and clean up the sandbox. + // Stop and clean up the sandbox on this side. On the source this is + // used after a successful migration; on the destination this is used + // when the migration was cancelled or failed. FINALIZE_ACTION_STOP = 1; - // Resume the sandbox (used on the destination to start running, or on the source to rollback). + // Resume the sandbox on this side. On the destination this completes + // a successful migration by bringing the migrated VM back to a + // running state; on the source this is used to roll back when the + // migration was cancelled or failed. FINALIZE_ACTION_RESUME = 2; } message FinalizeSandboxResponse {} message CreateDuplicateSocketRequest { - // Idempotency key; must match active LM session. + // Identifier for the active LM session. Must match the session_id used + // for the rest of this LM on this side. string session_id = 1; - // Serialized WSAProtocolInfo struct (opaque to clients). + // Serialized WSAProtocolInfo struct describing the source socket whose + // handle should be duplicated into the shim process. The exact layout + // is opaque to clients; the shim feeds it directly to WSASocket to + // create the duplicate. bytes protocol_info = 2; } From 77f7621cd1730bcab02f327e192b1f63cbdafc75 Mon Sep 17 00:00:00 2001 From: Harsh Rawat Date: Tue, 21 Apr 2026 01:03:34 +0530 Subject: [PATCH 3/3] fix protobuild error Signed-off-by: Harsh Rawat --- pkg/migration/migration.pb.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/pkg/migration/migration.pb.go b/pkg/migration/migration.pb.go index 0513d2cac4..feb617c98a 100644 --- a/pkg/migration/migration.pb.go +++ b/pkg/migration/migration.pb.go @@ -30,9 +30,7 @@ const ( type FinalizeAction int32 const ( - // No action specified. Servers should treat this as an error rather - // than silently picking a default, since the wrong choice can either - // destroy a running VM or leak a stopped one. + // No action specified. Servers should treat this as an error. FinalizeAction_FINALIZE_ACTION_UNSPECIFIED FinalizeAction = 0 // Stop and clean up the sandbox on this side. On the source this is // used after a successful migration; on the destination this is used @@ -440,8 +438,7 @@ type TransferSandboxResponse struct { // Monotonically increasing per-message counter on this stream. Useful // for de-duplication if the client reconnects mid-transfer. MessageID uint32 `protobuf:"varint,1,opt,name=message_id,json=messageId,proto3" json:"message_id,omitempty"` - // Event-specific message describing the current migration notification - // (e.g. progress milestone, state change). + // Event-specific message describing the current migration notification. Event string `protobuf:"bytes,2,opt,name=event,proto3" json:"event,omitempty"` // Populated when `event` indicates an error or a timeout; empty // otherwise.