diff --git a/Makefile b/Makefile index d8eb30b863..75d15c0846 100644 --- a/Makefile +++ b/Makefile @@ -84,6 +84,7 @@ out/delta.tar.gz: bin/init bin/vsockexec bin/cmd/gcs bin/cmd/gcstools bin/cmd/ho cp bin/cmd/gcs rootfs/bin/ cp bin/cmd/gcstools rootfs/bin/ cp bin/cmd/hooks/wait-paths rootfs/bin/ + cp /mnt/c/Users/kevpar/src/test/rebuf rootfs/bin/ for tool in $(GCS_TOOLS); do ln -s gcstools rootfs/bin/$$tool; done git -C $(SRCROOT) rev-parse HEAD > rootfs/info/gcs.commit && \ git -C $(SRCROOT) rev-parse --abbrev-ref HEAD > rootfs/info/gcs.branch && \ diff --git a/Protobuild.toml b/Protobuild.toml index 17145bb258..2c5b41dec2 100644 --- a/Protobuild.toml +++ b/Protobuild.toml @@ -7,7 +7,7 @@ generators = ["go", "go-grpc"] # defaults are "/usr/local/include" and "/usr/include", which don't exist on Windows. # override defaults to supress errors about non-existant directories. - after = [] + # after = [] # This section maps protobuf imports to Go packages. [packages] @@ -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/internal/save", ] generators = ["go", "go-ttrpc"] diff --git a/cmd/containerd-shim-runhcs-v1/options/runhcs.pb.go b/cmd/containerd-shim-runhcs-v1/options/runhcs.pb.go index d991411613..8e30c9d1ec 100644 --- a/cmd/containerd-shim-runhcs-v1/options/runhcs.pb.go +++ b/cmd/containerd-shim-runhcs-v1/options/runhcs.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.23.2 +// protoc-gen-go v1.28.1 +// protoc v3.21.12 // source: github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options/runhcs.proto package options @@ -190,7 +190,8 @@ type Options struct { // UTC. NoInheritHostTimezone bool `protobuf:"varint,19,opt,name=no_inherit_host_timezone,json=noInheritHostTimezone,proto3" json:"no_inherit_host_timezone,omitempty"` // scrub_logs enables removing environment variables and other potentially sensitive information from logs - ScrubLogs bool `protobuf:"varint,20,opt,name=scrub_logs,json=scrubLogs,proto3" json:"scrub_logs,omitempty"` + ScrubLogs bool `protobuf:"varint,20,opt,name=scrub_logs,json=scrubLogs,proto3" json:"scrub_logs,omitempty"` + RestorePath string `protobuf:"bytes,21,opt,name=restore_path,json=restorePath,proto3" json:"restore_path,omitempty"` } func (x *Options) Reset() { @@ -365,6 +366,13 @@ func (x *Options) GetScrubLogs() bool { return false } +func (x *Options) GetRestorePath() string { + if x != nil { + return x.RestorePath + } + return "" +} + // ProcessDetails contains additional information about a process. This is the additional // info returned in the Pids query. type ProcessDetails struct { @@ -489,7 +497,7 @@ var file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_options_runh 0x6f, 0x12, 0x14, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x72, 0x75, 0x6e, 0x68, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd9, 0x09, 0x0a, 0x07, 0x4f, 0x70, 0x74, + 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xfc, 0x09, 0x0a, 0x07, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, 0x62, 0x75, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x64, 0x65, 0x62, 0x75, 0x67, 0x12, 0x46, 0x0a, 0x0a, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, @@ -556,50 +564,52 @@ var file_github_com_Microsoft_hcsshim_cmd_containerd_shim_runhcs_v1_options_runh 0x28, 0x08, 0x52, 0x15, 0x6e, 0x6f, 0x49, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x63, 0x72, 0x75, 0x62, 0x5f, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, - 0x63, 0x72, 0x75, 0x62, 0x4c, 0x6f, 0x67, 0x73, 0x1a, 0x4e, 0x0a, 0x20, 0x44, 0x65, 0x66, 0x61, - 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x41, 0x6e, 0x6e, 0x6f, - 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, - 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, - 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x29, 0x0a, 0x09, 0x44, 0x65, 0x62, 0x75, - 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x4e, 0x50, 0x49, 0x50, 0x45, 0x10, 0x00, - 0x12, 0x08, 0x0a, 0x04, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x45, 0x54, - 0x57, 0x10, 0x02, 0x22, 0x2f, 0x0a, 0x10, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x49, 0x73, - 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x52, 0x4f, 0x43, 0x45, - 0x53, 0x53, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x48, 0x59, 0x50, 0x45, 0x52, 0x56, 0x49, 0x53, - 0x4f, 0x52, 0x10, 0x01, 0x22, 0xb6, 0x03, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, - 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x6d, 0x61, 0x67, 0x65, - 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6d, 0x61, - 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, - 0x74, 0x12, 0x2b, 0x0a, 0x12, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, - 0x5f, 0x31, 0x30, 0x30, 0x5f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6b, - 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x31, 0x30, 0x30, 0x4e, 0x73, 0x12, 0x2e, - 0x0a, 0x13, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x5f, - 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x6d, 0x65, 0x6d, - 0x6f, 0x72, 0x79, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x46, - 0x0a, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, - 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x62, 0x79, 0x74, - 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1c, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, - 0x57, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, - 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x44, 0x0a, 0x1f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, - 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x73, 0x68, 0x61, - 0x72, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x1b, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x57, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x53, 0x65, - 0x74, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, - 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x09, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x10, 0x75, - 0x73, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x31, 0x30, 0x30, 0x5f, 0x6e, 0x73, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x31, - 0x30, 0x30, 0x4e, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x78, 0x65, 0x63, 0x5f, 0x69, 0x64, 0x18, - 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x78, 0x65, 0x63, 0x49, 0x64, 0x42, 0x44, 0x5a, - 0x42, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4d, 0x69, 0x63, 0x72, - 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2f, 0x68, 0x63, 0x73, 0x73, 0x68, 0x69, 0x6d, 0x2f, 0x63, 0x6d, - 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2d, 0x73, 0x68, 0x69, - 0x6d, 0x2d, 0x72, 0x75, 0x6e, 0x68, 0x63, 0x73, 0x2d, 0x76, 0x31, 0x2f, 0x6f, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x63, 0x72, 0x75, 0x62, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65, 0x73, 0x74, + 0x6f, 0x72, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, + 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x50, 0x61, 0x74, 0x68, 0x1a, 0x4e, 0x0a, 0x20, 0x44, + 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x41, + 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x29, 0x0a, 0x09, 0x44, + 0x65, 0x62, 0x75, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x4e, 0x50, 0x49, 0x50, + 0x45, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x07, 0x0a, + 0x03, 0x45, 0x54, 0x57, 0x10, 0x02, 0x22, 0x2f, 0x0a, 0x10, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, + 0x78, 0x49, 0x73, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x52, + 0x4f, 0x43, 0x45, 0x53, 0x53, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x48, 0x59, 0x50, 0x45, 0x52, + 0x56, 0x49, 0x53, 0x4f, 0x52, 0x10, 0x01, 0x22, 0xb6, 0x03, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x63, + 0x65, 0x73, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x6d, + 0x61, 0x67, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x69, 0x6d, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x64, 0x41, 0x74, 0x12, 0x2b, 0x0a, 0x12, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x5f, 0x31, 0x30, 0x30, 0x5f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x0f, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x31, 0x30, 0x30, 0x4e, + 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, + 0x69, 0x74, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, + 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x42, 0x79, 0x74, 0x65, + 0x73, 0x12, 0x46, 0x0a, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x77, 0x6f, 0x72, 0x6b, + 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, + 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1c, 0x6d, 0x65, 0x6d, + 0x6f, 0x72, 0x79, 0x57, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x50, 0x72, 0x69, + 0x76, 0x61, 0x74, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x44, 0x0a, 0x1f, 0x6d, 0x65, 0x6d, + 0x6f, 0x72, 0x79, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x74, 0x5f, + 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x1b, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x57, 0x6f, 0x72, 0x6b, 0x69, 0x6e, + 0x67, 0x53, 0x65, 0x74, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, + 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x49, 0x64, 0x12, 0x27, + 0x0a, 0x10, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x31, 0x30, 0x30, 0x5f, + 0x6e, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x54, 0x69, + 0x6d, 0x65, 0x31, 0x30, 0x30, 0x4e, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x78, 0x65, 0x63, 0x5f, + 0x69, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, 0x78, 0x65, 0x63, 0x49, 0x64, + 0x42, 0x44, 0x5a, 0x42, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4d, + 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2f, 0x68, 0x63, 0x73, 0x73, 0x68, 0x69, 0x6d, + 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2d, + 0x73, 0x68, 0x69, 0x6d, 0x2d, 0x72, 0x75, 0x6e, 0x68, 0x63, 0x73, 0x2d, 0x76, 0x31, 0x2f, 0x6f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/cmd/containerd-shim-runhcs-v1/options/runhcs.proto b/cmd/containerd-shim-runhcs-v1/options/runhcs.proto index 8546c61507..4cf29ff565 100644 --- a/cmd/containerd-shim-runhcs-v1/options/runhcs.proto +++ b/cmd/containerd-shim-runhcs-v1/options/runhcs.proto @@ -107,6 +107,8 @@ message Options { // scrub_logs enables removing environment variables and other potentially sensitive information from logs bool scrub_logs = 20; + + string restore_path = 21; } // ProcessDetails contains additional information about a process. This is the additional diff --git a/cmd/containerd-shim-runhcs-v1/pod.go b/cmd/containerd-shim-runhcs-v1/pod.go index 051d8aede0..1fc29a7083 100644 --- a/cmd/containerd-shim-runhcs-v1/pod.go +++ b/cmd/containerd-shim-runhcs-v1/pod.go @@ -12,6 +12,7 @@ import ( "github.com/Microsoft/hcsshim/internal/log" "github.com/Microsoft/hcsshim/internal/oci" + "github.com/Microsoft/hcsshim/internal/state" "github.com/Microsoft/hcsshim/internal/uvm" "github.com/Microsoft/hcsshim/osversion" "github.com/Microsoft/hcsshim/pkg/annotations" @@ -66,6 +67,9 @@ type shimPod interface { // return `errdefs.ErrFailedPrecondition`. Deleting the pod's sandbox task // is a no-op. DeleteTask(ctx context.Context, tid string) error + + StartSave(ctx context.Context, path string) error + CompleteSave(ctx context.Context, path string) error } func createPod(ctx context.Context, events publisher, req *task.CreateTaskRequest, s *specs.Spec) (_ shimPod, err error) { @@ -449,3 +453,66 @@ func (p *pod) DeleteTask(ctx context.Context, tid string) error { return nil } + +type podState struct { + ID string + Spec *specs.Spec +} + +func (p *pod) StartSave(ctx context.Context, path string) error { + if err := os.MkdirAll(path, 0755); err != nil { + return err + } + if p.host == nil { + return fmt.Errorf("can only save VM-isolated pods") + } + if err := p.host.StartSave(ctx, filepath.Join(path, "uvm")); err != nil { + return fmt.Errorf("save UVM: %w", err) + } + if err := p.sandboxTask.Save(ctx, filepath.Join(path, "sandboxTask")); err != nil { + return err + } + if err := state.Write(filepath.Join(path, "state.json"), + &podState{ + ID: p.id, + Spec: p.spec, + }); err != nil { + return err + } + return nil +} + +func (p *pod) CompleteSave(ctx context.Context, path string) error { + if err := os.MkdirAll(path, 0755); err != nil { + return err + } + if p.host == nil { + return fmt.Errorf("can only save VM-isolated pods") + } + if err := p.host.CompleteSave(ctx, filepath.Join(path, "uvm")); err != nil { + return fmt.Errorf("save UVM: %w", err) + } + return nil +} + +type standbyPod struct { + state *podState + host *uvm.UtilityVM +} + +func restorePod(ctx context.Context, path string, netNS string, scratchPath string, events publisher, req *task.CreateTaskRequest) (_ shimPod, err error) { + p := &pod{ + events: events, + id: req.ID, + } + p.host, err = uvm.RestoreUVM(ctx, filepath.Join(path, "uvm"), netNS, scratchPath, req.ID) + if err != nil { + return nil, err + } + state, err := state.Read[podState](filepath.Join(path, "state.json")) + if err != nil { + return nil, err + } + p.spec = state.Spec + return p, nil +} diff --git a/cmd/containerd-shim-runhcs-v1/pod_test.go b/cmd/containerd-shim-runhcs-v1/pod_test.go index 24223043af..cb1d2b2802 100644 --- a/cmd/containerd-shim-runhcs-v1/pod_test.go +++ b/cmd/containerd-shim-runhcs-v1/pod_test.go @@ -86,6 +86,14 @@ func (tsp *testShimPod) DeleteTask(ctx context.Context, tid string) error { return nil } +func (tsp *testShimPod) StartSave(ctx context.Context, path string) error { + return fmt.Errorf("not implemented") +} + +func (tsp *testShimPod) CompleteSave(ctx context.Context, path string) error { + return fmt.Errorf("not implemented") +} + // Pod tests func setupTestPodWithFakes(t *testing.T) (*pod, *testShimTask) { diff --git a/cmd/containerd-shim-runhcs-v1/saverestore.go b/cmd/containerd-shim-runhcs-v1/saverestore.go new file mode 100644 index 0000000000..974b0e99c0 --- /dev/null +++ b/cmd/containerd-shim-runhcs-v1/saverestore.go @@ -0,0 +1,52 @@ +package main + +import ( + "context" + "fmt" + "os" +) + +func (s *service) startSave(ctx context.Context, path string) error { + if err := os.MkdirAll(path, 0755); err != nil { + return err + } + v := s.taskOrPod.Load() + if v == nil { + return fmt.Errorf("invalid state: no pod") + } + p, ok := v.(shimPod) + if !ok { + return fmt.Errorf("only works with pod, not standalone task") + } + if err := p.StartSave(ctx, path); err != nil { + return err + } + return nil +} + +func (s *service) completeSave(ctx context.Context, path string) error { + if err := os.MkdirAll(path, 0755); err != nil { + return err + } + v := s.taskOrPod.Load() + if v == nil { + return fmt.Errorf("invalid state: no pod") + } + p, ok := v.(shimPod) + if !ok { + return fmt.Errorf("only works with pod, not standalone task") + } + if err := p.CompleteSave(ctx, path); err != nil { + return err + } + return nil +} + +func (s *service) restore(ctx context.Context, path string) error { + // p, err := restorePod(ctx, filepath.Join(path, "pod")) + // if err != nil { + // return err + // } + // s.standbyPod = p + return nil +} diff --git a/cmd/containerd-shim-runhcs-v1/serve.go b/cmd/containerd-shim-runhcs-v1/serve.go index 290f986c42..1c9731b033 100644 --- a/cmd/containerd-shim-runhcs-v1/serve.go +++ b/cmd/containerd-shim-runhcs-v1/serve.go @@ -26,6 +26,7 @@ import ( runhcsopts "github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options" "github.com/Microsoft/hcsshim/internal/extendedtask" hcslog "github.com/Microsoft/hcsshim/internal/log" + "github.com/Microsoft/hcsshim/internal/save" "github.com/Microsoft/hcsshim/internal/shimdiag" "github.com/Microsoft/hcsshim/pkg/octtrpc" ) @@ -193,6 +194,12 @@ var serveCommand = cli.Command{ return fmt.Errorf("failed to create new service: %w", err) } + if p := newShimOpts.RestorePath; p != "" { + if err := svc.restore(context.Background(), p); err != nil { + return fmt.Errorf("restore shim from state %q: %w", p, err) + } + } + s, err := ttrpc.NewServer(ttrpc.WithUnaryServerInterceptor(octtrpc.ServerInterceptor())) if err != nil { return err @@ -201,6 +208,7 @@ var serveCommand = cli.Command{ task.RegisterTaskService(s, svc) shimdiag.RegisterShimDiagService(s, svc) extendedtask.RegisterExtendedTaskService(s, svc) + save.RegisterSaveService(s, svc) sl, err := winio.ListenPipe(socket, nil) if err != nil { diff --git a/cmd/containerd-shim-runhcs-v1/service.go b/cmd/containerd-shim-runhcs-v1/service.go index d9f62e0ef9..031e5eedf1 100644 --- a/cmd/containerd-shim-runhcs-v1/service.go +++ b/cmd/containerd-shim-runhcs-v1/service.go @@ -18,6 +18,7 @@ import ( "github.com/Microsoft/hcsshim/internal/extendedtask" "github.com/Microsoft/hcsshim/internal/oc" + "github.com/Microsoft/hcsshim/internal/save" "github.com/Microsoft/hcsshim/internal/shimdiag" ) @@ -64,7 +65,8 @@ type service struct { // taskOrPod is either the `pod` this shim is tracking if `isSandbox == // true` or it is the `task` this shim is tracking. If no call to `Create` // has taken place yet `taskOrPod.Load()` MUST return `nil`. - taskOrPod atomic.Value + taskOrPod atomic.Value + standbyPod *standbyPod // cl is the create lock. Since each shim MUST only track a single task or // POD. `cl` is used to create the task or POD sandbox. It SHOULD NOT be @@ -79,6 +81,8 @@ type service struct { // gracefulShutdown dictates whether to shutdown gracefully and clean up resources // or exit immediately gracefulShutdown bool + + savePath string } var _ task.TaskService = &service{} @@ -92,7 +96,7 @@ func NewService(o ...ServiceOption) (svc *service, err error) { svc = &service{ events: opts.Events, tid: opts.TID, - isSandbox: opts.IsSandbox, + isSandbox: true, //opts.IsSandbox, shutdown: make(chan struct{}), } return svc, nil @@ -532,6 +536,39 @@ func (s *service) DiagPid(ctx context.Context, req *shimdiag.PidRequest) (*shimd }, nil } +func (s *service) StartSave(ctx context.Context, req *save.StartSaveRequest) (*save.StartSaveResponse, error) { + if s == nil { + return nil, nil + } + ctx, span := oc.StartSpan(ctx, "StartSave") //nolint:ineffassign,staticcheck + defer span.End() + + span.AddAttributes(trace.StringAttribute("tid", s.tid)) + span.AddAttributes(trace.StringAttribute("sandboxID", req.PodId)) + span.AddAttributes(trace.StringAttribute("path", req.Path)) + + err := s.startSave(ctx, req.Path) + s.savePath = req.Path + + return &save.StartSaveResponse{}, errdefs.ToGRPC(err) +} + +func (s *service) CompleteSave(ctx context.Context, req *save.CompleteSaveRequest) (*save.CompleteSaveResponse, error) { + if s == nil { + return nil, nil + } + ctx, span := oc.StartSpan(ctx, "CompleteSave") //nolint:ineffassign,staticcheck + defer span.End() + + span.AddAttributes(trace.StringAttribute("tid", s.tid)) + span.AddAttributes(trace.StringAttribute("sandboxID", req.PodId)) + + err := s.completeSave(ctx, s.savePath) + s.savePath = "" + + return &save.CompleteSaveResponse{}, errdefs.ToGRPC(err) +} + func (s *service) ComputeProcessorInfo(ctx context.Context, req *extendedtask.ComputeProcessorInfoRequest) (*extendedtask.ComputeProcessorInfoResponse, error) { ctx, span := oc.StartSpan(ctx, "ComputeProcessorInfo") defer span.End() diff --git a/cmd/containerd-shim-runhcs-v1/service_internal.go b/cmd/containerd-shim-runhcs-v1/service_internal.go index b66c04a716..b785f9f7ab 100644 --- a/cmd/containerd-shim-runhcs-v1/service_internal.go +++ b/cmd/containerd-shim-runhcs-v1/service_internal.go @@ -16,6 +16,7 @@ import ( typeurl "github.com/containerd/typeurl/v2" "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "google.golang.org/protobuf/types/known/emptypb" "google.golang.org/protobuf/types/known/timestamppb" @@ -84,72 +85,85 @@ func (s *service) createInternal(ctx context.Context, req *task.CreateTaskReques shimOpts = v.(*runhcsopts.Options) } - var spec specs.Spec - f, err := os.Open(filepath.Join(req.Bundle, "config.json")) + rawSpec, err := os.ReadFile(filepath.Join(req.Bundle, "config.json")) if err != nil { return nil, err } - if err := json.NewDecoder(f).Decode(&spec); err != nil { - f.Close() - return nil, err + var restoreSpec struct { + Typ string + Path string + NetNS string + ScratchPath string } - f.Close() - - spec = oci.UpdateSpecFromOptions(spec, shimOpts) - //expand annotations after defaults have been loaded in from options - err = oci.ProcessAnnotations(ctx, &spec) - // since annotation expansion is used to toggle security features - // raise it rather than suppress and move on - if err != nil { - return nil, errors.Wrap(err, "unable to process OCI Spec annotations") + if err := json.Unmarshal(rawSpec, &restoreSpec); err != nil { + return nil, err } - - // If sandbox isolation is set to hypervisor, make sure the HyperV option - // is filled in. This lessens the burden on Containerd to parse our shims - // options if we can set this ourselves. - if shimOpts.SandboxIsolation == runhcsopts.Options_HYPERVISOR { - if spec.Windows == nil { - spec.Windows = &specs.Windows{} - } - if spec.Windows.HyperV == nil { - spec.Windows.HyperV = &specs.WindowsHyperV{} + logrus.WithField("restoreSpec", restoreSpec).Info("RESTORESPEC") + restore := restoreSpec.Typ == "RESTORESPEC" + var spec specs.Spec + if !restore { + if err := json.Unmarshal(rawSpec, &spec); err != nil { + return nil, err } } - var layerFolders []string - if spec.Windows != nil { - layerFolders = spec.Windows.LayerFolders - } - if err := validateRootfsAndLayers(req.Rootfs, layerFolders); err != nil { - return nil, err - } + if !restore { + spec = oci.UpdateSpecFromOptions(spec, shimOpts) + //expand annotations after defaults have been loaded in from options + err = oci.ProcessAnnotations(ctx, &spec) + // since annotation expansion is used to toggle security features + // raise it rather than suppress and move on + if err != nil { + return nil, errors.Wrap(err, "unable to process OCI Spec annotations") + } - // Only work with Windows here. - // Parsing of the rootfs mount for Linux containers occurs later. - if spec.Linux == nil && len(req.Rootfs) > 0 { - // For Windows containers, we work with LayerFolders throughout - // much of the creation logic in the shim. If we were given a - // rootfs mount, convert it to LayerFolders here. - m := req.Rootfs[0] - if m.Type != "windows-layer" { - return nil, fmt.Errorf("unsupported Windows mount type: %s", m.Type) + // If sandbox isolation is set to hypervisor, make sure the HyperV option + // is filled in. This lessens the burden on Containerd to parse our shims + // options if we can set this ourselves. + if shimOpts.SandboxIsolation == runhcsopts.Options_HYPERVISOR { + if spec.Windows == nil { + spec.Windows = &specs.Windows{} + } + if spec.Windows.HyperV == nil { + spec.Windows.HyperV = &specs.WindowsHyperV{} + } } - source, parentLayerPaths, err := parseLegacyRootfsMount(m) - if err != nil { + var layerFolders []string + if spec.Windows != nil { + layerFolders = spec.Windows.LayerFolders + } + if err := validateRootfsAndLayers(req.Rootfs, layerFolders); err != nil { return nil, err } - // Append the parents - spec.Windows.LayerFolders = append(spec.Windows.LayerFolders, parentLayerPaths...) - // Append the scratch - spec.Windows.LayerFolders = append(spec.Windows.LayerFolders, source) - } + // Only work with Windows here. + // Parsing of the rootfs mount for Linux containers occurs later. + if spec.Linux == nil && len(req.Rootfs) > 0 { + // For Windows containers, we work with LayerFolders throughout + // much of the creation logic in the shim. If we were given a + // rootfs mount, convert it to LayerFolders here. + m := req.Rootfs[0] + if m.Type != "windows-layer" { + return nil, fmt.Errorf("unsupported Windows mount type: %s", m.Type) + } - // This is a Windows Argon make sure that we have a Root filled in. - if spec.Windows.HyperV == nil { - if spec.Root == nil { - spec.Root = &specs.Root{} + source, parentLayerPaths, err := parseLegacyRootfsMount(m) + if err != nil { + return nil, err + } + + // Append the parents + spec.Windows.LayerFolders = append(spec.Windows.LayerFolders, parentLayerPaths...) + // Append the scratch + spec.Windows.LayerFolders = append(spec.Windows.LayerFolders, source) + } + + // This is a Windows Argon make sure that we have a Root filled in. + if spec.Windows.HyperV == nil { + if spec.Root == nil { + spec.Root = &specs.Root{} + } } } @@ -172,7 +186,18 @@ func (s *service) createInternal(ctx context.Context, req *task.CreateTaskReques resp.Pid = uint32(e.Pid()) return resp, nil } - pod, err = createPod(ctx, s.events, req, &spec) + if restore { + pod, err = restorePod( + ctx, + filepath.Join(restoreSpec.Path, "sandbox"), + restoreSpec.NetNS, + restoreSpec.ScratchPath, + s.events, + req, + ) + } else { + pod, err = createPod(ctx, s.events, req, &spec) + } if err != nil { s.cl.Unlock() return nil, err diff --git a/cmd/containerd-shim-runhcs-v1/task.go b/cmd/containerd-shim-runhcs-v1/task.go index ce525a71f0..3f57b0502a 100644 --- a/cmd/containerd-shim-runhcs-v1/task.go +++ b/cmd/containerd-shim-runhcs-v1/task.go @@ -99,6 +99,8 @@ type shimTask interface { ProcessorInfo(ctx context.Context) (*processorInfo, error) // Update updates a task's container Update(ctx context.Context, req *task.UpdateTaskRequest) error + + Save(ctx context.Context, path string) error } type processorInfo struct { diff --git a/cmd/containerd-shim-runhcs-v1/task_hcs.go b/cmd/containerd-shim-runhcs-v1/task_hcs.go index 6d32957217..5ec3e05053 100644 --- a/cmd/containerd-shim-runhcs-v1/task_hcs.go +++ b/cmd/containerd-shim-runhcs-v1/task_hcs.go @@ -1056,3 +1056,10 @@ func (ht *hcsTask) updateWCOWContainerMount(ctx context.Context, resources *ctrd } return nil } + +func (ht *hcsTask) Save(ctx context.Context, path string) error { + if err := os.MkdirAll(path, 0755); err != nil { + return err + } + return nil +} diff --git a/cmd/containerd-shim-runhcs-v1/task_test.go b/cmd/containerd-shim-runhcs-v1/task_test.go index 66ab66734c..df4403822c 100644 --- a/cmd/containerd-shim-runhcs-v1/task_test.go +++ b/cmd/containerd-shim-runhcs-v1/task_test.go @@ -4,6 +4,7 @@ package main import ( "context" + "fmt" "time" "github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options" @@ -143,6 +144,10 @@ func (tst *testShimTask) Stats(ctx context.Context) (*stats.Statistics, error) { return getLCOWTestStats(), nil } +func (tst *testShimTask) Save(ctx context.Context, path string) error { + return fmt.Errorf("not implemented") +} + func getWCOWTestStats() *stats.Statistics { return &stats.Statistics{ Container: &stats.Statistics_Windows{ diff --git a/cmd/containerd-shim-runhcs-v1/task_wcow_podsandbox.go b/cmd/containerd-shim-runhcs-v1/task_wcow_podsandbox.go index 924f3e4215..46d2cfeb2b 100644 --- a/cmd/containerd-shim-runhcs-v1/task_wcow_podsandbox.go +++ b/cmd/containerd-shim-runhcs-v1/task_wcow_podsandbox.go @@ -4,6 +4,7 @@ package main import ( "context" + "fmt" "sync" "time" @@ -313,3 +314,7 @@ func (wpst *wcowPodSandboxTask) ProcessorInfo(ctx context.Context) (*processorIn count: wpst.host.ProcessorCount(), }, nil } + +func (wpst *wcowPodSandboxTask) Save(ctx context.Context, path string) error { + return fmt.Errorf("not implemented") +} diff --git a/cmd/gcs/main.go b/cmd/gcs/main.go index 25751763dd..7c3f3e8fae 100644 --- a/cmd/gcs/main.go +++ b/cmd/gcs/main.go @@ -182,9 +182,9 @@ func main() { "", "Logging Target: An optional file name/path. Omit for console output.") logFormat := flag.String("log-format", "text", "Logging Format: text or json") - useInOutErr := flag.Bool("use-inouterr", - false, - "If true use stdin/stdout for bridge communication and stderr for logging") + // useInOutErr := flag.Bool("use-inouterr", + // false, + // "If true use stdin/stdout for bridge communication and stderr for logging") v4 := flag.Bool("v4", false, "enable the v4 protocol support and v2 schema") rootMemReserveBytes := flag.Uint64("root-mem-reserve-bytes", 75*1024*1024, // 75Mib @@ -307,24 +307,6 @@ func main() { h := hcsv2.NewHost(rtime, tport, initialEnforcer, logWriter) b.AssignHandlers(mux, h) - var bridgeIn io.ReadCloser - var bridgeOut io.WriteCloser - if *useInOutErr { - bridgeIn = os.Stdin - bridgeOut = os.Stdout - } else { - const commandPort uint32 = 0x40000000 - bridgeCon, err := tport.Dial(commandPort) - if err != nil { - logrus.WithFields(logrus.Fields{ - "port": commandPort, - logrus.ErrorKey: err, - }).Fatal("failed to dial host vsock connection") - } - bridgeIn = bridgeCon - bridgeOut = bridgeCon - } - // Setup the UVM cgroups to protect against a workload taking all available // memory and causing the GCS to malfunction we create two cgroups: gcs, // containers. @@ -390,10 +372,22 @@ func main() { go readMemoryEvents(startTime, gefdFile, "/gcs", int64(*gcsMemLimitBytes), gcsControl) go readMemoryEvents(startTime, oomFile, "/containers", containersLimit, containersControl) - err = b.ListenAndServe(bridgeIn, bridgeOut) - if err != nil { - logrus.WithFields(logrus.Fields{ - logrus.ErrorKey: err, - }).Fatal("failed to serve gcs service") + + for { + const commandPort uint32 = 0x40000000 + bridgeCon, err := tport.Dial(commandPort) + if err != nil { + logrus.WithFields(logrus.Fields{ + "port": commandPort, + logrus.ErrorKey: err, + }).Error("failed to dial host vsock connection") + } + err = b.ListenAndServe(bridgeCon, bridgeCon) + if err != nil { + logrus.WithFields(logrus.Fields{ + logrus.ErrorKey: err, + }).Error("failed to serve gcs service") + } + time.Sleep(3 * time.Second) } } diff --git a/internal/gcs/bridge.go b/internal/gcs/bridge.go index d36d1fe42b..62c42acdac 100644 --- a/internal/gcs/bridge.go +++ b/internal/gcs/bridge.go @@ -246,7 +246,9 @@ func (brdg *bridge) RPC(ctx context.Context, proc rpcProc, req requestMessage, r } func (brdg *bridge) recvLoopRoutine() { - brdg.kill(brdg.recvLoop()) + err := brdg.recvLoop() + logrus.WithError(err).Warn("bridge recvLoop exited") + brdg.kill(err) // Fail any remaining RPCs. brdg.mu.Lock() rpcs := brdg.rpcs @@ -290,6 +292,7 @@ func (brdg *bridge) recvLoop() error { for { id, typ, b, err := readMessage(br) if err != nil { + logrus.WithError(err).Warn("bridge read disconnect") if err == io.EOF || isLocalDisconnectError(err) { return nil } diff --git a/internal/guest/bridge/bridge.go b/internal/guest/bridge/bridge.go index c6b982bc76..b5745ea22c 100644 --- a/internal/guest/bridge/bridge.go +++ b/internal/guest/bridge/bridge.go @@ -224,24 +224,32 @@ func (b *Bridge) AssignHandlers(mux *Mux, host *hcsv2.Host) { // messages and dispatches the appropriate handlers to handle each // event in an asynchronous manner. func (b *Bridge) ListenAndServe(bridgeIn io.ReadCloser, bridgeOut io.WriteCloser) error { + b.protVer = 0 + requestChan := make(chan *Request) - requestErrChan := make(chan error) + requestErrChan := make(chan error, 1) b.responseChan = make(chan bridgeResponse) - responseErrChan := make(chan error) + responseErrChan := make(chan error, 1) b.quitChan = make(chan bool) defer close(b.quitChan) defer bridgeOut.Close() - defer close(responseErrChan) + // defer close(responseErrChan) defer close(b.responseChan) - defer close(requestChan) - defer close(requestErrChan) + // defer close(requestChan) + // defer close(requestErrChan) defer bridgeIn.Close() // Receive bridge requests and schedule them to be processed. go func() { var recverr error + loop: for { + select { + case <-b.quitChan: + break loop + default: + } if atomic.LoadUint32(&b.hasQuitPending) == 0 { header := &prot.MessageHeader{} if err := binary.Read(bridgeIn, binary.LittleEndian, header); err != nil { @@ -335,30 +343,39 @@ func (b *Bridge) ListenAndServe(bridgeIn io.ReadCloser, bridgeOut io.WriteCloser }() // Process each bridge request async and create the response writer. go func() { - for req := range requestChan { - go func(r *Request) { - br := bridgeResponse{ - ctx: r.Context, - header: &prot.MessageHeader{ - Type: prot.GetResponseIdentifier(r.Header.Type), - ID: r.Header.ID, - }, - } - resp, err := b.Handler.ServeMsg(r) - if resp == nil { - resp = &prot.MessageResponseBase{} - } - resp.Base().ActivityID = r.ActivityID - if err != nil { - span := trace.FromContext(r.Context) - if span != nil { - oc.SetSpanStatus(span, err) + for { + select { + case req := <-requestChan: + go func(r *Request) { + br := bridgeResponse{ + ctx: r.Context, + header: &prot.MessageHeader{ + Type: prot.GetResponseIdentifier(r.Header.Type), + ID: r.Header.ID, + }, } - setErrorForResponseBase(resp.Base(), err) - } - br.response = resp - b.responseChan <- br - }(req) + resp, err := b.Handler.ServeMsg(r) + if resp == nil { + resp = &prot.MessageResponseBase{} + } + resp.Base().ActivityID = r.ActivityID + if err != nil { + span := trace.FromContext(r.Context) + if span != nil { + oc.SetSpanStatus(span, err) + } + setErrorForResponseBase(resp.Base(), err) + } + br.response = resp + select { + case b.responseChan <- br: + case <-b.quitChan: + return + } + }(req) + case <-b.quitChan: + return + } } }() // Process each bridge response sync. This channel is for request/response and publish workflows. diff --git a/internal/hcs/system.go b/internal/hcs/system.go index cf1db7da9a..1c9db47531 100644 --- a/internal/hcs/system.go +++ b/internal/hcs/system.go @@ -37,6 +37,8 @@ type System struct { exitError error os, typ, owner string startTime time.Time + + ModifyHook func(any) error } var _ cow.Container = &System{} @@ -850,6 +852,12 @@ func (computeSystem *System) Modify(ctx context.Context, config interface{}) err computeSystem.handleLock.RLock() defer computeSystem.handleLock.RUnlock() + if mh := computeSystem.ModifyHook; mh != nil { + if err := mh(config); err != nil { + return err + } + } + operation := "hcs::System::Modify" if computeSystem.handle == 0 { diff --git a/internal/save/doc.go b/internal/save/doc.go new file mode 100644 index 0000000000..16890c0915 --- /dev/null +++ b/internal/save/doc.go @@ -0,0 +1 @@ +package save diff --git a/internal/save/save.pb.go b/internal/save/save.pb.go new file mode 100644 index 0000000000..40ca103111 --- /dev/null +++ b/internal/save/save.pb.go @@ -0,0 +1,344 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.1 +// protoc v3.21.12 +// source: dev.azure.com/msazure/ContainerPlatform/_git/azcri.git/api/save/save.proto + +package save + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +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) +) + +type StartSaveRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + PodId string `protobuf:"bytes,1,opt,name=pod_id,json=podId,proto3" json:"pod_id,omitempty"` + Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` +} + +func (x *StartSaveRequest) Reset() { + *x = StartSaveRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StartSaveRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StartSaveRequest) ProtoMessage() {} + +func (x *StartSaveRequest) ProtoReflect() protoreflect.Message { + mi := &file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StartSaveRequest.ProtoReflect.Descriptor instead. +func (*StartSaveRequest) Descriptor() ([]byte, []int) { + return file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_rawDescGZIP(), []int{0} +} + +func (x *StartSaveRequest) GetPodId() string { + if x != nil { + return x.PodId + } + return "" +} + +func (x *StartSaveRequest) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +type StartSaveResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *StartSaveResponse) Reset() { + *x = StartSaveResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StartSaveResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StartSaveResponse) ProtoMessage() {} + +func (x *StartSaveResponse) ProtoReflect() protoreflect.Message { + mi := &file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StartSaveResponse.ProtoReflect.Descriptor instead. +func (*StartSaveResponse) Descriptor() ([]byte, []int) { + return file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_rawDescGZIP(), []int{1} +} + +type CompleteSaveRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + PodId string `protobuf:"bytes,1,opt,name=pod_id,json=podId,proto3" json:"pod_id,omitempty"` +} + +func (x *CompleteSaveRequest) Reset() { + *x = CompleteSaveRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CompleteSaveRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CompleteSaveRequest) ProtoMessage() {} + +func (x *CompleteSaveRequest) ProtoReflect() protoreflect.Message { + mi := &file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CompleteSaveRequest.ProtoReflect.Descriptor instead. +func (*CompleteSaveRequest) Descriptor() ([]byte, []int) { + return file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_rawDescGZIP(), []int{2} +} + +func (x *CompleteSaveRequest) GetPodId() string { + if x != nil { + return x.PodId + } + return "" +} + +type CompleteSaveResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *CompleteSaveResponse) Reset() { + *x = CompleteSaveResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CompleteSaveResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CompleteSaveResponse) ProtoMessage() {} + +func (x *CompleteSaveResponse) ProtoReflect() protoreflect.Message { + mi := &file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CompleteSaveResponse.ProtoReflect.Descriptor instead. +func (*CompleteSaveResponse) Descriptor() ([]byte, []int) { + return file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_rawDescGZIP(), []int{3} +} + +var File_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto protoreflect.FileDescriptor + +var file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_rawDesc = []byte{ + 0x0a, 0x4a, 0x64, 0x65, 0x76, 0x2e, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x6d, 0x73, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x2f, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, + 0x72, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2f, 0x5f, 0x67, 0x69, 0x74, 0x2f, 0x61, + 0x7a, 0x63, 0x72, 0x69, 0x2e, 0x67, 0x69, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x61, 0x76, + 0x65, 0x2f, 0x73, 0x61, 0x76, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x72, 0x75, 0x6e, 0x68, 0x63, 0x73, 0x2e, + 0x76, 0x31, 0x2e, 0x64, 0x69, 0x61, 0x67, 0x22, 0x3d, 0x0a, 0x10, 0x53, 0x74, 0x61, 0x72, 0x74, + 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x70, + 0x6f, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x70, 0x6f, 0x64, + 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x22, 0x13, 0x0a, 0x11, 0x53, 0x74, 0x61, 0x72, 0x74, 0x53, + 0x61, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2c, 0x0a, 0x13, 0x43, + 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x70, 0x6f, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x70, 0x6f, 0x64, 0x49, 0x64, 0x22, 0x16, 0x0a, 0x14, 0x43, 0x6f, 0x6d, + 0x70, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x32, 0xdf, 0x01, 0x0a, 0x04, 0x53, 0x61, 0x76, 0x65, 0x12, 0x66, 0x0a, 0x09, 0x53, 0x74, + 0x61, 0x72, 0x74, 0x53, 0x61, 0x76, 0x65, 0x12, 0x2b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x72, 0x75, 0x6e, 0x68, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x64, + 0x69, 0x61, 0x67, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, + 0x64, 0x2e, 0x72, 0x75, 0x6e, 0x68, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x64, 0x69, 0x61, 0x67, + 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x0c, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x61, + 0x76, 0x65, 0x12, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, + 0x72, 0x75, 0x6e, 0x68, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x64, 0x69, 0x61, 0x67, 0x2e, 0x43, + 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x64, 0x2e, + 0x72, 0x75, 0x6e, 0x68, 0x63, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x64, 0x69, 0x61, 0x67, 0x2e, 0x43, + 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2f, 0x68, 0x63, 0x73, 0x73, + 0x68, 0x69, 0x6d, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x73, 0x61, 0x76, + 0x65, 0x3b, 0x73, 0x61, 0x76, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_rawDescOnce sync.Once + file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_rawDescData = file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_rawDesc +) + +func file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_rawDescGZIP() []byte { + file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_rawDescOnce.Do(func() { + file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_rawDescData = protoimpl.X.CompressGZIP(file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_rawDescData) + }) + return file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_rawDescData +} + +var file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_goTypes = []interface{}{ + (*StartSaveRequest)(nil), // 0: containerd.runhcs.v1.diag.StartSaveRequest + (*StartSaveResponse)(nil), // 1: containerd.runhcs.v1.diag.StartSaveResponse + (*CompleteSaveRequest)(nil), // 2: containerd.runhcs.v1.diag.CompleteSaveRequest + (*CompleteSaveResponse)(nil), // 3: containerd.runhcs.v1.diag.CompleteSaveResponse +} +var file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_depIdxs = []int32{ + 0, // 0: containerd.runhcs.v1.diag.Save.StartSave:input_type -> containerd.runhcs.v1.diag.StartSaveRequest + 2, // 1: containerd.runhcs.v1.diag.Save.CompleteSave:input_type -> containerd.runhcs.v1.diag.CompleteSaveRequest + 1, // 2: containerd.runhcs.v1.diag.Save.StartSave:output_type -> containerd.runhcs.v1.diag.StartSaveResponse + 3, // 3: containerd.runhcs.v1.diag.Save.CompleteSave:output_type -> containerd.runhcs.v1.diag.CompleteSaveResponse + 2, // [2:4] is the sub-list for method output_type + 0, // [0:2] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_init() } +func file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_init() { + if File_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StartSaveRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StartSaveResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CompleteSaveRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CompleteSaveResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_rawDesc, + NumEnums: 0, + NumMessages: 4, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_goTypes, + DependencyIndexes: file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_depIdxs, + MessageInfos: file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_msgTypes, + }.Build() + File_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto = out.File + file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_rawDesc = nil + file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_goTypes = nil + file_dev_azure_com_msazure_ContainerPlatform__git_azcri_git_api_save_save_proto_depIdxs = nil +} diff --git a/internal/save/save.proto b/internal/save/save.proto new file mode 100644 index 0000000000..bf01c5aa3e --- /dev/null +++ b/internal/save/save.proto @@ -0,0 +1,22 @@ +syntax = "proto3"; + +package containerd.runhcs.v1.diag; +option go_package = "github.com/Microsoft/hcsshim/internal/save;save"; + +service Save { + rpc StartSave(StartSaveRequest) returns (StartSaveResponse); + rpc CompleteSave(CompleteSaveRequest) returns (CompleteSaveResponse); +} + +message StartSaveRequest { + string pod_id = 1; + string path = 2; +} + +message StartSaveResponse {} + +message CompleteSaveRequest { + string pod_id = 1; +} + +message CompleteSaveResponse {} \ No newline at end of file diff --git a/internal/save/save_ttrpc.pb.go b/internal/save/save_ttrpc.pb.go new file mode 100644 index 0000000000..1c6cefde76 --- /dev/null +++ b/internal/save/save_ttrpc.pb.go @@ -0,0 +1,56 @@ +// Code generated by protoc-gen-go-ttrpc. DO NOT EDIT. +// source: dev.azure.com/msazure/ContainerPlatform/_git/azcri.git/api/save/save.proto +package save + +import ( + context "context" + ttrpc "github.com/containerd/ttrpc" +) + +type SaveService interface { + StartSave(ctx context.Context, req *StartSaveRequest) (*StartSaveResponse, error) + CompleteSave(ctx context.Context, req *CompleteSaveRequest) (*CompleteSaveResponse, error) +} + +func RegisterSaveService(srv *ttrpc.Server, svc SaveService) { + srv.Register("containerd.runhcs.v1.diag.Save", map[string]ttrpc.Method{ + "StartSave": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req StartSaveRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.StartSave(ctx, &req) + }, + "CompleteSave": func(ctx context.Context, unmarshal func(interface{}) error) (interface{}, error) { + var req CompleteSaveRequest + if err := unmarshal(&req); err != nil { + return nil, err + } + return svc.CompleteSave(ctx, &req) + }, + }) +} + +type saveClient struct { + client *ttrpc.Client +} + +func NewSaveClient(client *ttrpc.Client) SaveService { + return &saveClient{ + client: client, + } +} +func (c *saveClient) StartSave(ctx context.Context, req *StartSaveRequest) (*StartSaveResponse, error) { + var resp StartSaveResponse + if err := c.client.Call(ctx, "containerd.runhcs.v1.diag.Save", "StartSave", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} +func (c *saveClient) CompleteSave(ctx context.Context, req *CompleteSaveRequest) (*CompleteSaveResponse, error) { + var resp CompleteSaveResponse + if err := c.client.Call(ctx, "containerd.runhcs.v1.diag.Save", "CompleteSave", req, &resp); err != nil { + return nil, err + } + return &resp, nil +} diff --git a/internal/state/state.go b/internal/state/state.go new file mode 100644 index 0000000000..98dc71b305 --- /dev/null +++ b/internal/state/state.go @@ -0,0 +1,29 @@ +package state + +import ( + "encoding/json" + "os" +) + +func Write[T any](path string, state *T) error { + j, err := json.Marshal(state) + if err != nil { + return err + } + if err := os.WriteFile(path, j, 0644); err != nil { + return err + } + return nil +} + +func Read[T any](path string) (*T, error) { + v := new(T) + j, err := os.ReadFile(path) + if err != nil { + return nil, err + } + if err := json.Unmarshal(j, v); err != nil { + return nil, err + } + return v, nil +} diff --git a/internal/uvm/create.go b/internal/uvm/create.go index 90b939703e..887d1be956 100644 --- a/internal/uvm/create.go +++ b/internal/uvm/create.go @@ -179,6 +179,8 @@ func (uvm *UtilityVM) OS() string { } func (uvm *UtilityVM) create(ctx context.Context, doc interface{}) error { + uvm.config = doc.(*hcsschema.ComputeSystem) + uvm.exitCh = make(chan struct{}) system, err := hcs.CreateComputeSystem(ctx, uvm.id, doc) if err != nil { @@ -191,6 +193,10 @@ func (uvm *UtilityVM) create(ctx context.Context, doc interface{}) error { } }() + system.ModifyHook = func(change any) error { + return updateConfig(uvm.config, change) + } + // Cache the VM ID of the utility VM. properties, err := system.Properties(ctx) if err != nil { @@ -215,6 +221,7 @@ func (uvm *UtilityVM) Close() error { return uvm.CloseCtx(context.Background()) // The context is used for all operations, including waits, so timeouts/cancellations may prevent // proper uVM cleanup. func (uvm *UtilityVM) CloseCtx(ctx context.Context) (err error) { + log.G(ctx).Info("CLOSECTX") ctx, span := oc.StartSpan(ctx, "uvm::Close") defer span.End() defer func() { oc.SetSpanStatus(span, err) }() @@ -394,6 +401,7 @@ func (uvm *UtilityVM) NoWritableFileShares() bool { // Closes the external GCS connection if it is being used and also closes the // listener for GCS connection. func (uvm *UtilityVM) CloseGCSConnection() (err error) { + logrus.Warn("YOU HAVE A BAD CONNECTION") if uvm.gc != nil { err = uvm.gc.Close() } diff --git a/internal/uvm/create_lcow.go b/internal/uvm/create_lcow.go index b11fffd6eb..bd8ffda4ce 100644 --- a/internal/uvm/create_lcow.go +++ b/internal/uvm/create_lcow.go @@ -594,9 +594,14 @@ func makeLCOWDoc(ctx context.Context, opts *OptionsLCOW, uvm *UtilityVM) (_ *hcs // Allow administrators and SYSTEM to bind to vsock sockets // so that we can create a GCS log socket. DefaultBindSecurityDescriptor: "D:P(A;;FA;;;SY)(A;;FA;;;BA)", + ServiceTable: map[string]hcsschema.HvSocketServiceConfig{ + "0000006d-facb-11e6-bd58-64006a7986d3": hcsschema.HvSocketServiceConfig{ + BindSecurityDescriptor: "D:P(A;;FA;;;SY)(A;;FA;;;BA)", + AllowWildcardBinds: true, + }, + }, }, }, - Plan9: &hcsschema.Plan9{}, }, }, } @@ -688,7 +693,7 @@ func makeLCOWDoc(ctx context.Context, opts *OptionsLCOW, uvm *UtilityVM) (_ *hcs } vmDebugging := false - if opts.ConsolePipe != "" { + if opts.ConsolePipe != "" || true { vmDebugging = true kernelArgs += " 8250_core.nr_uarts=1 8250_core.skip_txen_test=1 console=ttyS0,115200" doc.VirtualMachine.Devices.ComPorts = map[string]hcsschema.ComPort{ @@ -760,6 +765,13 @@ func makeLCOWDoc(ctx context.Context, opts *OptionsLCOW, uvm *UtilityVM) (_ *hcs kernelArgs += fmt.Sprintf(" nr_cpus=%d", opts.ProcessorCount) kernelArgs += ` brd.rd_nr=0 pmtmr=0 -- ` + initArgs + doc.VirtualMachine.Devices.ComPorts = map[string]hcsschema.ComPort{ + "0": { // Which is actually COM1 + NamedPipe: `\\.\pipe\vmpipe`, + }, + } + kernelArgs = "8250_core.nr_uarts=1 8250_core.skip_txen_test=1 console=ttyS0,115200 pci=off nr_cpus=2 brd.rd_nr=0 pmtmr=0 quiet -- -e 1 /bin/gcs -v4 -log-format json -loglevel debug" + if !opts.KernelDirect { doc.VirtualMachine.Chipset.Uefi = &hcsschema.Uefi{ BootThis: &hcsschema.UefiBootEntry{ @@ -867,10 +879,10 @@ func CreateLCOW(ctx context.Context, opts *OptionsLCOW) (_ *UtilityVM, err error if opts.ForwardStdout || opts.ForwardStderr { uvm.outputHandler = opts.OutputHandlerCreator(opts.Options) uvm.outputProcessingDone = make(chan struct{}) - uvm.outputListener, err = uvm.listenVsock(linuxLogVsockPort) - if err != nil { - return nil, err - } + // uvm.outputListener, err = uvm.listenVsock(linuxLogVsockPort) + // if err != nil { + // return nil, err + // } } if opts.UseGuestConnection { diff --git a/internal/uvm/saverestore.go b/internal/uvm/saverestore.go new file mode 100644 index 0000000000..983f1a8ad8 --- /dev/null +++ b/internal/uvm/saverestore.go @@ -0,0 +1,302 @@ +package uvm + +import ( + "context" + "encoding/json" + "fmt" + "os" + "path/filepath" + "regexp" + + "github.com/Microsoft/hcsshim/hcn" + "github.com/Microsoft/hcsshim/internal/gcs" + "github.com/Microsoft/hcsshim/internal/hcs" + "github.com/Microsoft/hcsshim/internal/hcs/schema1" + hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2" + "github.com/Microsoft/hcsshim/internal/protocol/guestrequest" + statepkg "github.com/Microsoft/hcsshim/internal/state" + "github.com/Microsoft/hcsshim/internal/uvm/scsi" + "github.com/Microsoft/hcsshim/internal/wclayer" + "github.com/sirupsen/logrus" +) + +func ensure_VirtualMachine(config *hcsschema.ComputeSystem) { + if config.VirtualMachine == nil { + config.VirtualMachine = &hcsschema.VirtualMachine{} + } +} + +func ensure_VirtualMachine_Devices(config *hcsschema.ComputeSystem) { + ensure_VirtualMachine(config) + if config.VirtualMachine.Devices == nil { + config.VirtualMachine.Devices = &hcsschema.Devices{} + } +} + +func ensure_VirtualMachine_Devices_NetworkAdapters(config *hcsschema.ComputeSystem) { + ensure_VirtualMachine_Devices(config) + if config.VirtualMachine.Devices.NetworkAdapters == nil { + config.VirtualMachine.Devices.NetworkAdapters = map[string]hcsschema.NetworkAdapter{} + } +} + +func ensure_VirtualMachine_Devices_Scsi(config *hcsschema.ComputeSystem) { + ensure_VirtualMachine_Devices(config) + if config.VirtualMachine.Devices.Scsi == nil { + config.VirtualMachine.Devices.Scsi = map[string]hcsschema.Scsi{} + } +} + +func ensure_VirtualMachine_Devices_Scsi_K(config *hcsschema.ComputeSystem, k1 string) { + ensure_VirtualMachine_Devices_Scsi(config) + if _, ok := config.VirtualMachine.Devices.Scsi[k1]; !ok { + config.VirtualMachine.Devices.Scsi[k1] = hcsschema.Scsi{Attachments: map[string]hcsschema.Attachment{}} + } +} + +func updateConfig(config *hcsschema.ComputeSystem, changeAny any) error { + change, ok := changeAny.(*hcsschema.ModifySettingRequest) + if !ok { + return fmt.Errorf("bad type for change request: %T", changeAny) + } + switch change.RequestType { + case guestrequest.RequestTypeAdd: + var matched bool + for _, s := range []struct { + regex string + f func(*hcsschema.ComputeSystem, []string, any) error + }{ + { + regex: `^VirtualMachine/Devices/NetworkAdapters/([^/]+)$`, + f: func(config *hcsschema.ComputeSystem, m []string, settings any) error { + ensure_VirtualMachine_Devices_NetworkAdapters(config) + _, ok := config.VirtualMachine.Devices.NetworkAdapters[m[1]] + if ok { + return fmt.Errorf("collision") + } + v, ok := settings.(hcsschema.NetworkAdapter) + if !ok { + return fmt.Errorf("bad type: %T", settings) + } + config.VirtualMachine.Devices.NetworkAdapters[m[1]] = v + return nil + }, + }, + { + regex: `^VirtualMachine/Devices/Scsi/([^/]+)/Attachments/([^/]+)$`, + f: func(config *hcsschema.ComputeSystem, m []string, settings any) error { + ensure_VirtualMachine_Devices_Scsi_K(config, m[1]) + _, ok := config.VirtualMachine.Devices.Scsi[m[1]].Attachments[m[2]] + if ok { + return fmt.Errorf("collision") + } + v, ok := settings.(hcsschema.Attachment) + if !ok { + return fmt.Errorf("bad type: %T", settings) + } + config.VirtualMachine.Devices.Scsi[m[1]].Attachments[m[2]] = v + return nil + }, + }, + } { + if m := regexp.MustCompile(s.regex).FindStringSubmatch(change.ResourcePath); m != nil { + matched = true + if err := s.f(config, m, change.Settings); err != nil { + return fmt.Errorf("update error for %s: %w", change.ResourcePath, err) + } + break + } + } + if !matched { + return fmt.Errorf("unrecognized update path: %s with payload type %T", change.ResourcePath, change.Settings) + } + j, err := json.Marshal(config) + if err != nil { + return err + } + j2, err := json.Marshal(change) + if err != nil { + return err + } + logrus.WithFields(logrus.Fields{ + "config": string(j), + "change": string(j2), + }).Info("UPDATED CONFIG") + case guestrequest.RequestTypeRemove: + return fmt.Errorf("unrecognized update path: %s with payload type %T", change.ResourcePath, change.Settings) + default: + return fmt.Errorf("unrecognized request type: %s", change.RequestType) + } + return nil +} + +type uvmState struct { + ProcessorCount int32 + PhysicallyBacked bool + DevicesPhysicallyBacked bool + Protocol uint32 + GuestCaps schema1.GuestDefinedCapabilities + ContainerCounter uint64 + SCSIControllerCount uint32 + ReservedSCSISlots []scsi.Slot + MountCounter uint64 +} + +func (uvm *UtilityVM) StartSave(ctx context.Context, path string) error { + if err := os.MkdirAll(path, 0755); err != nil { + return err + } + if err := uvm.hcsSystem.Pause(ctx); err != nil { + return err + } + if err := statepkg.Write(filepath.Join(path, "config.json"), uvm.config); err != nil { + return err + } + state := uvmState{ + ProcessorCount: uvm.processorCount, + PhysicallyBacked: uvm.physicallyBacked, + DevicesPhysicallyBacked: uvm.devicesPhysicallyBacked, + Protocol: uvm.protocol, + GuestCaps: uvm.guestCaps, + ContainerCounter: uvm.containerCounter, + SCSIControllerCount: uvm.scsiControllerCount, + ReservedSCSISlots: uvm.reservedSCSISlots, + MountCounter: uvm.mountCounter, + } + if err := statepkg.Write(filepath.Join(path, "state.json"), &state); err != nil { + return err + } + if err := uvm.SCSIManager.Save(ctx, filepath.Join(path, "scsi")); err != nil { + return err + } + if err := uvm.hcsSystem.Save(ctx, &hcsschema.SaveOptions{SaveStateFilePath: filepath.Join(path, "vm.state")}); err != nil { + return err + } + return nil +} + +func (uvm *UtilityVM) CompleteSave(ctx context.Context, path string) error { + if err := os.MkdirAll(path, 0755); err != nil { + return err + } + if err := uvm.hcsSystem.Resume(ctx); err != nil { + return err + } + return nil +} + +func RestoreUVM(ctx context.Context, path string, netNS string, scratchPath string, id string) (*UtilityVM, error) { + state, err := statepkg.Read[uvmState](filepath.Join(path, "state.json")) + if err != nil { + return nil, err + } + uvm := &UtilityVM{ + id: fmt.Sprintf("%s@vm", id), + owner: "shim-reborn", + operatingSystem: "linux", + scsiControllerCount: state.SCSIControllerCount, + physicallyBacked: state.PhysicallyBacked, + devicesPhysicallyBacked: state.DevicesPhysicallyBacked, + reservedSCSISlots: state.ReservedSCSISlots, + processorCount: state.ProcessorCount, + // protocol: state.Protocol, + // guestCaps: state.GuestCaps, + containerCounter: state.ContainerCounter, + mountCounter: state.MountCounter, + exitCh: make(chan struct{}), + outputProcessingDone: make(chan struct{}), + outputHandler: parseLogrus(&Options{ID: fmt.Sprintf("%s@vm", id)}), + } + config, err := statepkg.Read[hcsschema.ComputeSystem](filepath.Join(path, "config.json")) + if err != nil { + return nil, err + } + + // NICs + hcnNamespace, err := hcn.GetNamespaceByID(netNS) + if err != nil { + return nil, err + } + uvm.namespaces = map[string]*namespaceInfo{ + hcnNamespace.Id: {make(map[string]*nicInfo)}, + } + endpoints, err := GetNamespaceEndpoints(ctx, netNS) + if err != nil { + return nil, err + } + if len(endpoints) != len(config.VirtualMachine.Devices.NetworkAdapters) { + return nil, fmt.Errorf("expected %d NICs but got %d", len(config.VirtualMachine.Devices.NetworkAdapters), len(endpoints)) + } + if len(endpoints) != 1 { + return nil, fmt.Errorf("can only support one endpoint right now") + } + e := endpoints[0] + for k := range config.VirtualMachine.Devices.NetworkAdapters { + config.VirtualMachine.Devices.NetworkAdapters[k] = hcsschema.NetworkAdapter{ + EndpointId: e.Id, + MacAddress: e.MacAddress, + } + uvm.namespaces[hcnNamespace.Id].nics[k] = &nicInfo{ + ID: k, + Endpoint: e, + } + } + + // Scratch disk + type disk struct { + controller string + lun string + } + var writableDisks []disk + for i := range config.VirtualMachine.Devices.Scsi { + for j := range config.VirtualMachine.Devices.Scsi[i].Attachments { + if !config.VirtualMachine.Devices.Scsi[i].Attachments[j].ReadOnly { + writableDisks = append(writableDisks, disk{i, j}) + } + } + } + if len(writableDisks) != 1 { + return nil, fmt.Errorf("expected 1 writable disk but got %d", len(writableDisks)) + } + d := writableDisks[0] + scratch := config.VirtualMachine.Devices.Scsi[d.controller].Attachments[d.lun] + scratch.Path = scratchPath + config.VirtualMachine.Devices.Scsi[d.controller].Attachments[d.lun] = scratch + if err := wclayer.GrantVmAccess(ctx, fmt.Sprintf("%s@vm", id), scratchPath); err != nil { + return nil, err + } + + config.VirtualMachine.RestoreState = &hcsschema.RestoreState{SaveStateFilePath: filepath.Join(path, "vm.state")} + + system, err := hcs.CreateComputeSystem(ctx, uvm.id, config) + if err != nil { + return nil, err + } + properties, err := system.Properties(ctx) + if err != nil { + return nil, err + } + uvm.runtimeID = properties.RuntimeID + uvm.hcsSystem = system + uvm.config = config + + // uvm.outputListener, err = uvm.listenVsock(linuxLogVsockPort) + // if err != nil { + // return nil, err + // } + uvm.gcListener, err = uvm.listenVsock(gcs.LinuxGcsVsockPort) + if err != nil { + return nil, err + } + + if err := uvm.Start(ctx); err != nil { + return nil, err + } + + uvm.SCSIRestorer, err = scsi.RestoreManager(ctx, filepath.Join(path, "scsi")) + if err != nil { + return nil, err + } + + return uvm, nil +} diff --git a/internal/uvm/scsi/manager.go b/internal/uvm/scsi/manager.go index bad893d594..9d3377ec69 100644 --- a/internal/uvm/scsi/manager.go +++ b/internal/uvm/scsi/manager.go @@ -4,9 +4,12 @@ import ( "context" "errors" "fmt" + "os" + "path/filepath" "strings" "sync" + statepkg "github.com/Microsoft/hcsshim/internal/state" "github.com/Microsoft/hcsshim/internal/wclayer" ) @@ -308,3 +311,145 @@ func parseExtensibleVirtualDiskPath(hostPath string) (evdType, mountPath string, } return trimmedPath[:separatorIndex], trimmedPath[separatorIndex+1:], nil } + +type scsiStateAttachmentConfig struct { + Path string + ReadOnly bool + Type string +} + +type scsiStateAttachment struct { + Controller uint + LUN uint + Config *scsiStateAttachmentConfig + RefCount uint +} + +type scsiStateMountConfig struct { + ReadOnly bool + Options []string +} + +type scsiStateMount struct { + Controller uint + LUN uint + Path string + Config scsiStateMountConfig + RefCount uint +} + +type scsiState struct { + Attachments []scsiStateAttachment + Mounts []scsiStateMount + MountFmt string +} + +func (m *Manager) Save(ctx context.Context, path string) error { + if err := os.MkdirAll(path, 0755); err != nil { + return err + } + state := scsiState{} + for i := range m.attachManager.slots { + for j := range m.attachManager.slots[i] { + s := m.attachManager.slots[i][j] + if s != nil && s.refCount > 0 { + a := scsiStateAttachment{ + Controller: s.controller, + LUN: s.lun, + RefCount: s.refCount, + } + if s.config != nil { + a.Config = &scsiStateAttachmentConfig{ + Path: s.config.path, + ReadOnly: s.config.readOnly, + Type: s.config.typ, + } + } + state.Attachments = append(state.Attachments, a) + } + } + } + for _, m := range m.mountManager.mounts { + state.Mounts = append(state.Mounts, scsiStateMount{ + Controller: m.controller, + LUN: m.lun, + Path: m.path, + Config: scsiStateMountConfig{ + ReadOnly: m.config.readOnly, + Options: m.config.options, + }, + RefCount: m.refCount, + }) + } + state.MountFmt = m.mountManager.mountFmt + if err := statepkg.Write(filepath.Join(path, "state.json"), &state); err != nil { + return err + } + return nil +} + +type ManagerRestorer struct { + state *scsiState +} + +func RestoreManager(ctx context.Context, path string) (*ManagerRestorer, error) { + state, err := statepkg.Read[scsiState](filepath.Join(path, "state.json")) + if err != nil { + return nil, err + } + return &ManagerRestorer{state}, nil +} + +func (mr *ManagerRestorer) Restore( + ctx context.Context, + hb HostBackend, + gb GuestBackend, + numControllers int, + numLUNsPerController int, +) *Manager { + am := &attachManager{ + attacher: hb, + unplugger: gb, + numControllers: numControllers, + numLUNsPerController: numLUNsPerController, + slots: make([][]*attachment, numControllers), + } + for i := range am.slots { + am.slots[i] = make([]*attachment, numLUNsPerController) + } + for _, a := range mr.state.Attachments { + am.slots[a.Controller][a.LUN] = &attachment{ + controller: a.Controller, + lun: a.LUN, + config: &attachConfig{ + path: a.Config.Path, + readOnly: a.Config.ReadOnly, + typ: a.Config.Type, + }, + waitCh: make(chan struct{}), + refCount: a.RefCount, + } + close(am.slots[a.Controller][a.LUN].waitCh) + } + mm := &mountManager{ + mounter: gb, + mounts: make([]*mount, 0, len(mr.state.Mounts)), + mountFmt: mr.state.MountFmt, + } + for i, m := range mr.state.Mounts { + mm.mounts = append(mm.mounts, &mount{ + path: m.Path, + index: i, + controller: m.Controller, + lun: m.LUN, + config: &mountConfig{ + readOnly: m.Config.ReadOnly, + options: m.Config.Options, + }, + waitCh: make(chan struct{}), + refCount: m.RefCount, + }) + close(mm.mounts[i].waitCh) + } + return &Manager{am, mm} +} diff --git a/internal/uvm/start.go b/internal/uvm/start.go index 5ea8c0f166..96818634b3 100644 --- a/internal/uvm/start.go +++ b/internal/uvm/start.go @@ -300,6 +300,7 @@ func (uvm *UtilityVM) Start(ctx context.Context) (err error) { } // Initialize the SCSIManager. + hb := scsi.NewHCSHostBackend(uvm.hcsSystem) var gb scsi.GuestBackend if uvm.gc != nil { gb = scsi.NewBridgeGuestBackend(uvm.gc, uvm.OS()) @@ -310,17 +311,27 @@ func (uvm *UtilityVM) Start(ctx context.Context) (err error) { if uvm.OS() == "linux" { guestMountFmt = "/run/mounts/scsi/m%d" } - mgr, err := scsi.NewManager( - scsi.NewHCSHostBackend(uvm.hcsSystem), - gb, - int(uvm.scsiControllerCount), - 64, // LUNs per controller, fixed by Hyper-V. - guestMountFmt, - uvm.reservedSCSISlots) - if err != nil { - return fmt.Errorf("creating scsi manager: %w", err) + if uvm.SCSIRestorer != nil { + uvm.SCSIManager = uvm.SCSIRestorer.Restore( + ctx, + hb, + gb, + int(uvm.scsiControllerCount), + 64, // LUNs per controller, fixed by Hyper-V. + ) + } else { + mgr, err := scsi.NewManager( + hb, + gb, + int(uvm.scsiControllerCount), + 64, // LUNs per controller, fixed by Hyper-V. + guestMountFmt, + uvm.reservedSCSISlots) + if err != nil { + return fmt.Errorf("creating scsi manager: %w", err) + } + uvm.SCSIManager = mgr } - uvm.SCSIManager = mgr if uvm.confidentialUVMOptions != nil && uvm.OS() == "linux" { copts := []ConfidentialUVMOpt{ diff --git a/internal/uvm/types.go b/internal/uvm/types.go index 4b99c15843..ef77845db3 100644 --- a/internal/uvm/types.go +++ b/internal/uvm/types.go @@ -13,6 +13,7 @@ import ( "github.com/Microsoft/hcsshim/internal/gcs" "github.com/Microsoft/hcsshim/internal/hcs" "github.com/Microsoft/hcsshim/internal/hcs/schema1" + hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2" "github.com/Microsoft/hcsshim/internal/hns" "github.com/Microsoft/hcsshim/internal/uvm/scsi" ) @@ -34,6 +35,8 @@ type namespaceInfo struct { // UtilityVM is the object used by clients representing a utility VM type UtilityVM struct { + config *hcsschema.ComputeSystem + id string // Identifier for the utility VM (user supplied or generated) runtimeID guid.GUID // Hyper-V VM ID owner string // Owner for the utility VM (user supplied or generated) @@ -90,6 +93,7 @@ type UtilityVM struct { // SCSI devices that are mapped into a Windows or Linux utility VM SCSIManager *scsi.Manager + SCSIRestorer *scsi.ManagerRestorer scsiControllerCount uint32 // Number of SCSI controllers in the utility VM reservedSCSISlots []scsi.Slot diff --git a/pkg/securitypolicy/securitypolicyenforcer.go b/pkg/securitypolicy/securitypolicyenforcer.go index b9a8561eba..eb308db271 100644 --- a/pkg/securitypolicy/securitypolicyenforcer.go +++ b/pkg/securitypolicy/securitypolicyenforcer.go @@ -114,7 +114,7 @@ func newSecurityPolicyFromBase64JSON(base64EncodedPolicy string) (*SecurityPolic securityPolicy := new(SecurityPolicy) err = json.Unmarshal(jsonPolicy, securityPolicy) if err != nil { - return nil, errors.Wrap(err, "unable to unmarshal JSON policy") + return nil, fmt.Errorf("unable to unmarshal JSON policy: %w: %s", jsonPolicy) } return securityPolicy, nil diff --git a/vendor/github.com/Microsoft/go-winio/hvsock.go b/vendor/github.com/Microsoft/go-winio/hvsock.go index c881916583..3acaf4c1ca 100644 --- a/vendor/github.com/Microsoft/go-winio/hvsock.go +++ b/vendor/github.com/Microsoft/go-winio/hvsock.go @@ -18,6 +18,7 @@ import ( "github.com/Microsoft/go-winio/internal/socket" "github.com/Microsoft/go-winio/pkg/guid" + "github.com/sirupsen/logrus" ) const afHVSock = 34 // AF_HYPERV @@ -194,6 +195,18 @@ func newHVSocket() (*win32File, error) { return f, nil } +func cs(h windows.Handle) error { + fmt.Printf("setting CS on %x\n", h) + var v uint32 = 1 + return windows.Setsockopt( + h, + 1, + 4, + (*byte)(unsafe.Pointer(&v)), + 4, + ) +} + // ListenHvsock listens for connections on the specified hvsock address. func ListenHvsock(addr *HvsockAddr) (_ *HvsockListener, err error) { l := &HvsockListener{addr: *addr} @@ -206,6 +219,13 @@ func ListenHvsock(addr *HvsockAddr) (_ *HvsockListener, err error) { if err != nil { return nil, l.opErr("listen", os.NewSyscallError("socket", err)) } + logrus.WithFields(logrus.Fields{ + "vmID": addr.VMID.String(), + "serviceID": addr.ServiceID.String(), + }).Info("enabled CS on socket") + if err = cs(windows.Handle(sock.handle)); err != nil { + return nil, l.opErr("listen", os.NewSyscallError("setsockopt", err)) + } err = syscall.Listen(sock.handle, 16) if err != nil { return nil, l.opErr("listen", os.NewSyscallError("listen", err))