From f607641a6e6d8240c2f82484fb8ef7d4d01151de Mon Sep 17 00:00:00 2001 From: "fupan.lfp" Date: Tue, 15 Jun 2021 19:14:21 +0800 Subject: [PATCH] shimv2: fix the issue bring by updating containerd vendor Fix the mismatch bring by the upgrading of vendor of containerd, cgroup and runtime spec. Fixes: #1441 Signed-off-by: fupan.lfp --- src/runtime/cli/kata-env.go | 6 +- src/runtime/containerd-shim-v2/create.go | 2 +- src/runtime/containerd-shim-v2/metrics.go | 54 +- .../containerd-shim-v2/metrics_test.go | 4 +- src/runtime/containerd-shim-v2/service.go | 41 +- src/runtime/containerd-shim-v2/utils.go | 4 +- src/runtime/go.sum | 3 + .../checkpoint-restore/go-criu/v4/.gitignore | 5 + .../checkpoint-restore/go-criu/v4/.travis.yml | 28 + .../checkpoint-restore/go-criu/v4/LICENSE | 201 ++ .../checkpoint-restore/go-criu/v4/Makefile | 60 + .../checkpoint-restore/go-criu/v4/README.md | 75 + .../checkpoint-restore/go-criu/v4/go.mod | 5 + .../checkpoint-restore/go-criu/v4/go.sum | 2 + .../checkpoint-restore/go-criu/v4/main.go | 259 ++ .../checkpoint-restore/go-criu/v4/notify.go | 63 + .../go-criu/v4/rpc/rpc.pb.go | 1667 +++++++++++++ .../pkg/runtimeoptions/v1/api.pb.go | 397 ++++ .../pkg/runtimeoptions/v1/api.proto | 25 + .../github.com/mrunalp/fileutils/.gitignore | 1 + .../github.com/mrunalp/fileutils/LICENSE | 191 ++ .../github.com/mrunalp/fileutils/MAINTAINERS | 1 + .../github.com/mrunalp/fileutils/README.md | 5 + .../github.com/mrunalp/fileutils/fileutils.go | 168 ++ .../github.com/mrunalp/fileutils/go.mod | 3 + .../github.com/mrunalp/fileutils/idtools.go | 54 + .../runc/libcontainer/README.md | 330 +++ .../opencontainers/runc/libcontainer/SPEC.md | 465 ++++ .../libcontainer/apparmor/apparmor_linux.go | 54 + .../apparmor/apparmor_unsupported.go | 20 + .../libcontainer/capabilities/capabilities.go | 96 + .../capabilities/capabilities_unsupported.go | 3 + .../libcontainer/configs/validate/rootless.go | 90 + .../configs/validate/validator.go | 239 ++ .../runc/libcontainer/console_linux.go | 41 + .../runc/libcontainer/container.go | 173 ++ .../runc/libcontainer/container_linux.go | 2095 +++++++++++++++++ .../runc/libcontainer/criu_opts_linux.go | 32 + .../opencontainers/runc/libcontainer/error.go | 70 + .../runc/libcontainer/factory.go | 44 + .../runc/libcontainer/factory_linux.go | 443 ++++ .../runc/libcontainer/generic_error.go | 92 + .../runc/libcontainer/init_linux.go | 544 +++++ .../runc/libcontainer/intelrdt/cmt.go | 25 + .../runc/libcontainer/intelrdt/intelrdt.go | 816 +++++++ .../runc/libcontainer/intelrdt/mbm.go | 35 + .../runc/libcontainer/intelrdt/monitoring.go | 86 + .../runc/libcontainer/intelrdt/stats.go | 59 + .../runc/libcontainer/keys/keyctl.go | 47 + .../runc/libcontainer/logs/logs.go | 102 + .../runc/libcontainer/message_linux.go | 89 + .../runc/libcontainer/network_linux.go | 103 + .../runc/libcontainer/notify_linux.go | 87 + .../runc/libcontainer/notify_linux_v2.go | 102 + .../runc/libcontainer/process.go | 115 + .../runc/libcontainer/process_linux.go | 651 +++++ .../runc/libcontainer/restored_process.go | 129 + .../runc/libcontainer/rootfs_linux.go | 1047 ++++++++ .../runc/libcontainer/setns_init_linux.go | 90 + .../runc/libcontainer/stacktrace/capture.go | 27 + .../runc/libcontainer/stacktrace/frame.go | 38 + .../libcontainer/stacktrace/stacktrace.go | 5 + .../runc/libcontainer/standard_init_linux.go | 222 ++ .../runc/libcontainer/state_linux.go | 245 ++ .../runc/libcontainer/stats_linux.go | 13 + .../opencontainers/runc/libcontainer/sync.go | 101 + .../opencontainers/runc/types/events.go | 155 ++ .../github.com/syndtr/gocapability/LICENSE | 24 + .../gocapability/capability/capability.go | 133 ++ .../capability/capability_linux.go | 642 +++++ .../capability/capability_noop.go | 19 + .../syndtr/gocapability/capability/enum.go | 309 +++ .../gocapability/capability/enum_gen.go | 138 ++ .../gocapability/capability/syscall_linux.go | 154 ++ src/runtime/vendor/modules.txt | 17 + src/runtime/virtcontainers/cgroups.go | 2 +- src/runtime/virtcontainers/cgroups_test.go | 9 +- src/runtime/virtcontainers/kata_agent.go | 4 +- src/runtime/virtcontainers/kata_agent_test.go | 10 +- .../virtcontainers/physical_endpoint.go | 4 +- .../pkg/agent/protocols/grpc/agent.pb.go | 387 +-- .../pkg/agent/protocols/grpc/oci.pb.go | 536 ++--- .../pkg/agent/protocols/grpc/utils.go | 9 - .../pkg/agent/protocols/grpc/utils_test.go | 20 - .../pkg/agent/protocols/types.pb.go | 62 +- .../virtcontainers/pkg/cgroups/manager.go | 36 +- .../virtcontainers/pkg/cgroups/utils.go | 26 +- .../virtcontainers/pkg/cgroups/utils_test.go | 14 +- src/runtime/virtcontainers/pkg/oci/utils.go | 28 - .../virtcontainers/pkg/oci/utils_test.go | 157 -- src/runtime/virtcontainers/types/sandbox.go | 3 + 91 files changed, 14488 insertions(+), 799 deletions(-) create mode 100644 src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/.gitignore create mode 100644 src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/.travis.yml create mode 100644 src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/LICENSE create mode 100644 src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/Makefile create mode 100644 src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/README.md create mode 100644 src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/go.mod create mode 100644 src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/go.sum create mode 100644 src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/main.go create mode 100644 src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/notify.go create mode 100644 src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/rpc/rpc.pb.go create mode 100644 src/runtime/vendor/github.com/containerd/containerd/pkg/runtimeoptions/v1/api.pb.go create mode 100644 src/runtime/vendor/github.com/containerd/containerd/pkg/runtimeoptions/v1/api.proto create mode 100644 src/runtime/vendor/github.com/mrunalp/fileutils/.gitignore create mode 100644 src/runtime/vendor/github.com/mrunalp/fileutils/LICENSE create mode 100644 src/runtime/vendor/github.com/mrunalp/fileutils/MAINTAINERS create mode 100644 src/runtime/vendor/github.com/mrunalp/fileutils/README.md create mode 100644 src/runtime/vendor/github.com/mrunalp/fileutils/fileutils.go create mode 100644 src/runtime/vendor/github.com/mrunalp/fileutils/go.mod create mode 100644 src/runtime/vendor/github.com/mrunalp/fileutils/idtools.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/README.md create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/SPEC.md create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_linux.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_unsupported.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/capabilities/capabilities.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/capabilities/capabilities_unsupported.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/console_linux.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/container.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/criu_opts_linux.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/error.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/factory.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/factory_linux.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/generic_error.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/init_linux.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/cmt.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/mbm.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/monitoring.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/stats.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/keys/keyctl.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/logs/logs.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/message_linux.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/network_linux.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/notify_linux.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/notify_linux_v2.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/process.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/process_linux.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/restored_process.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/setns_init_linux.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/capture.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/frame.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/stacktrace.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/standard_init_linux.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/state_linux.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/stats_linux.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/libcontainer/sync.go create mode 100644 src/runtime/vendor/github.com/opencontainers/runc/types/events.go create mode 100644 src/runtime/vendor/github.com/syndtr/gocapability/LICENSE create mode 100644 src/runtime/vendor/github.com/syndtr/gocapability/capability/capability.go create mode 100644 src/runtime/vendor/github.com/syndtr/gocapability/capability/capability_linux.go create mode 100644 src/runtime/vendor/github.com/syndtr/gocapability/capability/capability_noop.go create mode 100644 src/runtime/vendor/github.com/syndtr/gocapability/capability/enum.go create mode 100644 src/runtime/vendor/github.com/syndtr/gocapability/capability/enum_gen.go create mode 100644 src/runtime/vendor/github.com/syndtr/gocapability/capability/syscall_linux.go diff --git a/src/runtime/cli/kata-env.go b/src/runtime/cli/kata-env.go index 2daf51d8d616..38167547550b 100644 --- a/src/runtime/cli/kata-env.go +++ b/src/runtime/cli/kata-env.go @@ -265,9 +265,9 @@ func getMemoryInfo() MemoryInfo { } return MemoryInfo{ - Total: mi.MemTotal, - Free: mi.MemFree, - Available: mi.MemAvailable, + Total: *mi.MemTotal, + Free: *mi.MemFree, + Available: *mi.MemAvailable, } } diff --git a/src/runtime/containerd-shim-v2/create.go b/src/runtime/containerd-shim-v2/create.go index fa1311871aa8..c96f0345eabd 100644 --- a/src/runtime/containerd-shim-v2/create.go +++ b/src/runtime/containerd-shim-v2/create.go @@ -22,9 +22,9 @@ import ( otelTrace "go.opentelemetry.io/otel/trace" // only register the proto type + crioption "github.com/containerd/containerd/pkg/runtimeoptions/v1" _ "github.com/containerd/containerd/runtime/linux/runctypes" _ "github.com/containerd/containerd/runtime/v2/runc/options" - crioption "github.com/containerd/cri-containerd/pkg/api/runtimeoptions/v1" "github.com/kata-containers/kata-containers/src/runtime/pkg/katautils" vc "github.com/kata-containers/kata-containers/src/runtime/virtcontainers" diff --git a/src/runtime/containerd-shim-v2/metrics.go b/src/runtime/containerd-shim-v2/metrics.go index cfe1da0f816c..86476ad3acd8 100644 --- a/src/runtime/containerd-shim-v2/metrics.go +++ b/src/runtime/containerd-shim-v2/metrics.go @@ -8,7 +8,7 @@ package containerdshim import ( "context" - "github.com/containerd/cgroups" + cgroupsv1 "github.com/containerd/cgroups/stats/v1" "github.com/containerd/typeurl" google_protobuf "github.com/gogo/protobuf/types" @@ -31,11 +31,11 @@ func marshalMetrics(ctx context.Context, s *service, containerID string) (*googl return data, nil } -func statsToMetrics(stats *vc.ContainerStats) *cgroups.Metrics { - metrics := &cgroups.Metrics{} +func statsToMetrics(stats *vc.ContainerStats) *cgroupsv1.Metrics { + metrics := &cgroupsv1.Metrics{} if stats.CgroupStats != nil { - metrics = &cgroups.Metrics{ + metrics = &cgroupsv1.Metrics{ Hugetlb: setHugetlbStats(stats.CgroupStats.HugetlbStats), Pids: setPidsStats(stats.CgroupStats.PidsStats), CPU: setCPUStats(stats.CgroupStats.CPUStats), @@ -49,12 +49,12 @@ func statsToMetrics(stats *vc.ContainerStats) *cgroups.Metrics { return metrics } -func setHugetlbStats(vcHugetlb map[string]vc.HugetlbStats) []*cgroups.HugetlbStat { - var hugetlbStats []*cgroups.HugetlbStat +func setHugetlbStats(vcHugetlb map[string]vc.HugetlbStats) []*cgroupsv1.HugetlbStat { + var hugetlbStats []*cgroupsv1.HugetlbStat for _, v := range vcHugetlb { hugetlbStats = append( hugetlbStats, - &cgroups.HugetlbStat{ + &cgroupsv1.HugetlbStat{ Usage: v.Usage, Max: v.MaxUsage, Failcnt: v.Failcnt, @@ -64,8 +64,8 @@ func setHugetlbStats(vcHugetlb map[string]vc.HugetlbStats) []*cgroups.HugetlbSta return hugetlbStats } -func setPidsStats(vcPids vc.PidsStats) *cgroups.PidsStat { - pidsStats := &cgroups.PidsStat{ +func setPidsStats(vcPids vc.PidsStats) *cgroupsv1.PidsStat { + pidsStats := &cgroupsv1.PidsStat{ Current: vcPids.Current, Limit: vcPids.Limit, } @@ -73,19 +73,19 @@ func setPidsStats(vcPids vc.PidsStats) *cgroups.PidsStat { return pidsStats } -func setCPUStats(vcCPU vc.CPUStats) *cgroups.CPUStat { +func setCPUStats(vcCPU vc.CPUStats) *cgroupsv1.CPUStat { var perCPU []uint64 perCPU = append(perCPU, vcCPU.CPUUsage.PercpuUsage...) - cpuStats := &cgroups.CPUStat{ - Usage: &cgroups.CPUUsage{ + cpuStats := &cgroupsv1.CPUStat{ + Usage: &cgroupsv1.CPUUsage{ Total: vcCPU.CPUUsage.TotalUsage, Kernel: vcCPU.CPUUsage.UsageInKernelmode, User: vcCPU.CPUUsage.UsageInUsermode, PerCPU: perCPU, }, - Throttling: &cgroups.Throttle{ + Throttling: &cgroupsv1.Throttle{ Periods: vcCPU.ThrottlingData.Periods, ThrottledPeriods: vcCPU.ThrottlingData.ThrottledPeriods, ThrottledTime: vcCPU.ThrottlingData.ThrottledTime, @@ -95,27 +95,27 @@ func setCPUStats(vcCPU vc.CPUStats) *cgroups.CPUStat { return cpuStats } -func setMemoryStats(vcMemory vc.MemoryStats) *cgroups.MemoryStat { - memoryStats := &cgroups.MemoryStat{ - Usage: &cgroups.MemoryEntry{ +func setMemoryStats(vcMemory vc.MemoryStats) *cgroupsv1.MemoryStat { + memoryStats := &cgroupsv1.MemoryStat{ + Usage: &cgroupsv1.MemoryEntry{ Limit: vcMemory.Usage.Limit, Usage: vcMemory.Usage.Usage, Max: vcMemory.Usage.MaxUsage, Failcnt: vcMemory.Usage.Failcnt, }, - Swap: &cgroups.MemoryEntry{ + Swap: &cgroupsv1.MemoryEntry{ Limit: vcMemory.SwapUsage.Limit, Usage: vcMemory.SwapUsage.Usage, Max: vcMemory.SwapUsage.MaxUsage, Failcnt: vcMemory.SwapUsage.Failcnt, }, - Kernel: &cgroups.MemoryEntry{ + Kernel: &cgroupsv1.MemoryEntry{ Limit: vcMemory.KernelUsage.Limit, Usage: vcMemory.KernelUsage.Usage, Max: vcMemory.KernelUsage.MaxUsage, Failcnt: vcMemory.KernelUsage.Failcnt, }, - KernelTCP: &cgroups.MemoryEntry{ + KernelTCP: &cgroupsv1.MemoryEntry{ Limit: vcMemory.KernelTCPUsage.Limit, Usage: vcMemory.KernelTCPUsage.Usage, Max: vcMemory.KernelTCPUsage.MaxUsage, @@ -145,8 +145,8 @@ func setMemoryStats(vcMemory vc.MemoryStats) *cgroups.MemoryStat { return memoryStats } -func setBlkioStats(vcBlkio vc.BlkioStats) *cgroups.BlkIOStat { - blkioStats := &cgroups.BlkIOStat{ +func setBlkioStats(vcBlkio vc.BlkioStats) *cgroupsv1.BlkIOStat { + blkioStats := &cgroupsv1.BlkIOStat{ IoServiceBytesRecursive: copyBlkio(vcBlkio.IoServiceBytesRecursive), IoServicedRecursive: copyBlkio(vcBlkio.IoServicedRecursive), IoQueuedRecursive: copyBlkio(vcBlkio.IoQueuedRecursive), @@ -160,10 +160,10 @@ func setBlkioStats(vcBlkio vc.BlkioStats) *cgroups.BlkIOStat { return blkioStats } -func copyBlkio(s []vc.BlkioStatEntry) []*cgroups.BlkIOEntry { - ret := make([]*cgroups.BlkIOEntry, len(s)) +func copyBlkio(s []vc.BlkioStatEntry) []*cgroupsv1.BlkIOEntry { + ret := make([]*cgroupsv1.BlkIOEntry, len(s)) for i, v := range s { - ret[i] = &cgroups.BlkIOEntry{ + ret[i] = &cgroupsv1.BlkIOEntry{ Op: v.Op, Major: v.Major, Minor: v.Minor, @@ -174,10 +174,10 @@ func copyBlkio(s []vc.BlkioStatEntry) []*cgroups.BlkIOEntry { return ret } -func setNetworkStats(vcNetwork []*vc.NetworkStats) []*cgroups.NetworkStat { - networkStats := make([]*cgroups.NetworkStat, len(vcNetwork)) +func setNetworkStats(vcNetwork []*vc.NetworkStats) []*cgroupsv1.NetworkStat { + networkStats := make([]*cgroupsv1.NetworkStat, len(vcNetwork)) for i, v := range vcNetwork { - networkStats[i] = &cgroups.NetworkStat{ + networkStats[i] = &cgroupsv1.NetworkStat{ Name: v.Name, RxBytes: v.RxBytes, RxPackets: v.RxPackets, diff --git a/src/runtime/containerd-shim-v2/metrics_test.go b/src/runtime/containerd-shim-v2/metrics_test.go index d40ba6347e06..e2a9177a207f 100644 --- a/src/runtime/containerd-shim-v2/metrics_test.go +++ b/src/runtime/containerd-shim-v2/metrics_test.go @@ -10,7 +10,7 @@ import ( "context" "testing" - "github.com/containerd/cgroups" + "github.com/containerd/cgroups/stats/v1" vc "github.com/kata-containers/kata-containers/src/runtime/virtcontainers" "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/vcmock" "github.com/stretchr/testify/assert" @@ -29,7 +29,7 @@ func TestStatNetworkMetric(t *testing.T) { }, } - expectedNetwork := []*cgroups.NetworkStat{ + expectedNetwork := []*v1.NetworkStat{ { Name: "test-network", RxBytes: 10, diff --git a/src/runtime/containerd-shim-v2/service.go b/src/runtime/containerd-shim-v2/service.go index 1ad93446803e..839d15055c12 100644 --- a/src/runtime/containerd-shim-v2/service.go +++ b/src/runtime/containerd-shim-v2/service.go @@ -68,7 +68,7 @@ var shimLog = logrus.WithFields(logrus.Fields{ }) // New returns a new shim service that can be used via GRPC -func New(ctx context.Context, id string, publisher events.Publisher) (cdshim.Shim, error) { +func New(ctx context.Context, id string, publisher cdshim.Publisher, shutdown func()) (cdshim.Shim, error) { shimLog = shimLog.WithFields(logrus.Fields{ "sandbox": id, "pid": os.Getpid(), @@ -84,8 +84,6 @@ func New(ctx context.Context, id string, publisher events.Publisher) (cdshim.Shi vci.SetLogger(ctx, shimLog) katautils.SetLogger(ctx, shimLog, shimLog.Logger.Level) - ctx, cancel := context.WithCancel(ctx) - s := &service{ id: id, pid: uint32(os.Getpid()), @@ -93,7 +91,7 @@ func New(ctx context.Context, id string, publisher events.Publisher) (cdshim.Shi containers: make(map[string]*container), events: make(chan interface{}, chSize), ec: make(chan exit, bufferSize), - cancel: cancel, + cancel: shutdown, } go s.processExits() @@ -138,7 +136,7 @@ type service struct { id string } -func newCommand(ctx context.Context, containerdBinary, id, containerdAddress string) (*sysexec.Cmd, error) { +func newCommand(ctx context.Context, id, containerdBinary, containerdAddress string) (*sysexec.Cmd, error) { ns, err := namespaces.NamespaceRequired(ctx) if err != nil { return nil, err @@ -176,13 +174,13 @@ func newCommand(ctx context.Context, containerdBinary, id, containerdAddress str // StartShim willl start a kata shimv2 daemon which will implemented the // ShimV2 APIs such as create/start/update etc containers. -func (s *service) StartShim(ctx context.Context, id, containerdBinary, containerdAddress string) (string, error) { +func (s *service) StartShim(ctx context.Context, opts cdshim.StartOpts) (_ string, retErr error) { bundlePath, err := os.Getwd() if err != nil { return "", err } - address, err := getAddress(ctx, bundlePath, id) + address, err := getAddress(ctx, bundlePath, opts.Address, opts.ID) if err != nil { return "", err } @@ -193,26 +191,41 @@ func (s *service) StartShim(ctx context.Context, id, containerdBinary, container return address, nil } - cmd, err := newCommand(ctx, containerdBinary, id, containerdAddress) + cmd, err := newCommand(ctx, opts.ID, opts.ContainerdBinary, opts.Address) if err != nil { return "", err } - address, err = cdshim.SocketAddress(ctx, id) + address, err = cdshim.SocketAddress(ctx, opts.Address, opts.ID) if err != nil { return "", err } socket, err := cdshim.NewSocket(address) + if err != nil { - return "", err + if !cdshim.SocketEaddrinuse(err) { + return "", err + } + if err := cdshim.RemoveSocket(address); err != nil { + return "", errors.Wrap(err, "remove already used socket") + } + if socket, err = cdshim.NewSocket(address); err != nil { + return "", err + } } - defer socket.Close() + + defer func() { + if retErr != nil { + socket.Close() + _ = cdshim.RemoveSocket(address) + } + }() + f, err := socket.File() if err != nil { return "", err } - defer f.Close() cmd.ExtraFiles = append(cmd.ExtraFiles, f) @@ -220,7 +233,7 @@ func (s *service) StartShim(ctx context.Context, id, containerdBinary, container return "", err } defer func() { - if err != nil { + if retErr != nil { cmd.Process.Kill() } }() @@ -290,7 +303,7 @@ func getTopic(e interface{}) string { func trace(ctx context.Context, name string) (otelTrace.Span, context.Context) { if ctx == nil { - logrus.WithField("type", "bug").Error("trace called before context set") + logrus.WithFields(logrus.Fields{"type": "bug", "name": name}).Error("called before context set") ctx = context.Background() } tracer := otel.Tracer("kata") diff --git a/src/runtime/containerd-shim-v2/utils.go b/src/runtime/containerd-shim-v2/utils.go index d3001fda7180..7b135b5a2858 100644 --- a/src/runtime/containerd-shim-v2/utils.go +++ b/src/runtime/containerd-shim-v2/utils.go @@ -78,7 +78,7 @@ func validBundle(containerID, bundlePath string) (string, error) { return resolved, nil } -func getAddress(ctx context.Context, bundlePath, id string) (string, error) { +func getAddress(ctx context.Context, bundlePath, address, id string) (string, error) { var err error // Checks the MUST and MUST NOT from OCI runtime specification @@ -101,7 +101,7 @@ func getAddress(ctx context.Context, bundlePath, id string) (string, error) { if err != nil { return "", err } - address, err := cdshim.SocketAddress(ctx, sandboxID) + address, err := cdshim.SocketAddress(ctx, address, sandboxID) if err != nil { return "", err } diff --git a/src/runtime/go.sum b/src/runtime/go.sum index ad012f00d826..522ca1604f80 100644 --- a/src/runtime/go.sum +++ b/src/runtime/go.sum @@ -120,6 +120,7 @@ github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v4 v4.1.0 h1:WW2B2uxx9KWF6bGlHqhm8Okiafwwx7Y2kcpn8lCpjgo= github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= @@ -585,6 +586,7 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mrunalp/fileutils v0.5.0 h1:NKzVxiH7eSk+OQ4M+ZYW1K6h27RUV3MI6NUTsHhU6Z4= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= @@ -743,6 +745,7 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 h1:b6uOv7YOFK0TYG7HtkIgExQo+2RdLuwRft63jn2HWj8= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= diff --git a/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/.gitignore b/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/.gitignore new file mode 100644 index 000000000000..f1c90e3d5ff1 --- /dev/null +++ b/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/.gitignore @@ -0,0 +1,5 @@ +test/test +test/piggie +test/phaul +image +rpc/rpc.proto diff --git a/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/.travis.yml b/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/.travis.yml new file mode 100644 index 000000000000..85e0cde3790a --- /dev/null +++ b/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/.travis.yml @@ -0,0 +1,28 @@ +language: go +dist: bionic +os: + - linux +go: + - "1.14.x" + - "1.13.x" + - tip +env: + # Run the tests with CRIU master and criu-dev + - CRIU_BRANCH="master" + - CRIU_BRANCH="criu-dev" +install: + - sudo apt-get update + - sudo apt-get install -y libprotobuf-dev libprotobuf-c0-dev protobuf-c-compiler protobuf-compiler python-protobuf libnl-3-dev libnet-dev libcap-dev + - make install.tools + - go get github.com/checkpoint-restore/go-criu + - git clone --single-branch -b ${CRIU_BRANCH} https://github.com/checkpoint-restore/criu.git + - cd criu; make + - sudo install -D -m 755 criu/criu /usr/sbin/ + - cd .. +script: + # This builds the code without running the tests. + - make lint build phaul test/test test/phaul test/piggie + # Run actual test as root as it uses CRIU. + - sudo make test phaul-test + # This builds crit-go + - make -C crit-go/magic-gen lint build magicgen test diff --git a/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/LICENSE b/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/LICENSE new file mode 100644 index 000000000000..8dada3edaf50 --- /dev/null +++ b/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/Makefile b/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/Makefile new file mode 100644 index 000000000000..10356304b1f0 --- /dev/null +++ b/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/Makefile @@ -0,0 +1,60 @@ +GO ?= go +CC ?= gcc +ifeq ($(GOPATH),) +export GOPATH := $(shell $(GO) env GOPATH) +endif +FIRST_GOPATH := $(firstword $(subst :, ,$(GOPATH))) +GOBIN := $(shell $(GO) env GOBIN) +ifeq ($(GOBIN),) + GOBIN := $(FIRST_GOPATH)/bin +endif + +all: build test phaul phaul-test + +lint: + @golint -set_exit_status . test phaul +build: + @$(GO) build -v + +test/piggie: test/piggie.c + @$(CC) $^ -o $@ + +test/test: test/main.go + @$(GO) build -v -o test/test test/main.go + +test: test/test test/piggie + mkdir -p image + test/piggie + test/test dump `pidof piggie` image + test/test restore image + pkill -9 piggie || : + +phaul: + @cd phaul; go build -v + +test/phaul: test/phaul-main.go + @$(GO) build -v -o test/phaul test/phaul-main.go + +phaul-test: test/phaul test/piggie + rm -rf image + test/piggie + test/phaul `pidof piggie` + pkill -9 piggie || : + +clean: + @rm -f test/test test/piggie test/phaul + @rm -rf image + @rm -f rpc/rpc.proto + +install.tools: + if [ ! -x "$(GOBIN)/golint" ]; then \ + $(GO) get -u golang.org/x/lint/golint; \ + fi + +rpc/rpc.proto: + curl -s https://raw.githubusercontent.com/checkpoint-restore/criu/master/images/rpc.proto -o $@ + +rpc/rpc.pb.go: rpc/rpc.proto + protoc --go_out=. $^ + +.PHONY: build test clean lint phaul diff --git a/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/README.md b/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/README.md new file mode 100644 index 000000000000..ace01564c55e --- /dev/null +++ b/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/README.md @@ -0,0 +1,75 @@ +[![master](https://travis-ci.org/checkpoint-restore/go-criu.svg?branch=master)](https://travis-ci.org/checkpoint-restore/go-criu) + +## go-criu -- Go bindings for [CRIU](https://criu.org/) + +This repository provides Go bindings for CRIU. The code is based on the Go based PHaul +implementation from the CRIU repository. For easier inclusion into other Go projects the +CRIU Go bindings have been moved to this repository. + +The Go bindings provide an easy way to use the CRIU RPC calls from Go without the need +to set up all the infrastructure to make the actual RPC connection to CRIU. + +The following example would print the version of CRIU: +``` + c := criu.MakeCriu() + version, err := c.GetCriuVersion() + fmt.Println(version) +``` +or to just check if at least a certain CRIU version is installed: +``` + c := criu.MakeCriu() + result, err := c.IsCriuAtLeast(31100) +``` + +## Releases + +The first go-criu release was 3.11 based on CRIU 3.11. The initial plan +was to follow CRIU so that go-criu would carry the same version number as +CRIU. + +As go-criu is imported in other projects and as Go modules are expected +to follow Semantic Versioning go-criu will also follow Semantic Versioning +starting with the 4.0.0 release. + +4.0.0 is based on CRIU 3.14 + +## How to contribute + +While bug fixes can first be identified via an "issue", that is not required. +It's ok to just open up a PR with the fix, but make sure you include the same +information you would have included in an issue - like how to reproduce it. + +PRs for new features should include some background on what use cases the +new code is trying to address. When possible and when it makes sense, try to +break-up larger PRs into smaller ones - it's easier to review smaller +code changes. But only if those smaller ones make sense as stand-alone PRs. + +Regardless of the type of PR, all PRs should include: +* well documented code changes +* additional testcases. Ideally, they should fail w/o your code change applied +* documentation changes + +Squash your commits into logical pieces of work that might want to be reviewed +separate from the rest of the PRs. Ideally, each commit should implement a +single idea, and the PR branch should pass the tests at every commit. GitHub +makes it easy to review the cumulative effect of many commits; so, when in +doubt, use smaller commits. + +PRs that fix issues should include a reference like `Closes #XXXX` in the +commit message so that github will automatically close the referenced issue +when the PR is merged. + +Contributors must assert that they are in compliance with the [Developer +Certificate of Origin 1.1](http://developercertificate.org/). This is achieved +by adding a "Signed-off-by" line containing the contributor's name and e-mail +to every commit message. Your signature certifies that you wrote the patch or +otherwise have the right to pass it on as an open-source patch. + +### License and copyright + +Unless mentioned otherwise in a specific file's header, all code in +this project is released under the Apache 2.0 license. + +The author of a change remains the copyright holder of their code +(no copyright assignment). The list of authors and contributors can be +retrieved from the git commit history and in some cases, the file headers. diff --git a/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/go.mod b/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/go.mod new file mode 100644 index 000000000000..4966669068f4 --- /dev/null +++ b/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/go.mod @@ -0,0 +1,5 @@ +module github.com/checkpoint-restore/go-criu/v4 + +go 1.13 + +require github.com/golang/protobuf v1.3.5 diff --git a/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/go.sum b/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/go.sum new file mode 100644 index 000000000000..6124ed3e451b --- /dev/null +++ b/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/go.sum @@ -0,0 +1,2 @@ +github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= diff --git a/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/main.go b/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/main.go new file mode 100644 index 000000000000..d0a6da47837b --- /dev/null +++ b/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/main.go @@ -0,0 +1,259 @@ +package criu + +import ( + "errors" + "fmt" + "os" + "os/exec" + "strconv" + "syscall" + + "github.com/checkpoint-restore/go-criu/v4/rpc" + "github.com/golang/protobuf/proto" +) + +// Criu struct +type Criu struct { + swrkCmd *exec.Cmd + swrkSk *os.File + swrkPath string +} + +// MakeCriu returns the Criu object required for most operations +func MakeCriu() *Criu { + return &Criu{ + swrkPath: "criu", + } +} + +// SetCriuPath allows setting the path to the CRIU binary +// if it is in a non standard location +func (c *Criu) SetCriuPath(path string) { + c.swrkPath = path +} + +// Prepare sets up everything for the RPC communication to CRIU +func (c *Criu) Prepare() error { + fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_SEQPACKET, 0) + if err != nil { + return err + } + + cln := os.NewFile(uintptr(fds[0]), "criu-xprt-cln") + syscall.CloseOnExec(fds[0]) + srv := os.NewFile(uintptr(fds[1]), "criu-xprt-srv") + defer srv.Close() + + args := []string{"swrk", strconv.Itoa(fds[1])} + cmd := exec.Command(c.swrkPath, args...) + + err = cmd.Start() + if err != nil { + cln.Close() + return err + } + + c.swrkCmd = cmd + c.swrkSk = cln + + return nil +} + +// Cleanup cleans up +func (c *Criu) Cleanup() { + if c.swrkCmd != nil { + c.swrkSk.Close() + c.swrkSk = nil + c.swrkCmd.Wait() + c.swrkCmd = nil + } +} + +func (c *Criu) sendAndRecv(reqB []byte) ([]byte, int, error) { + cln := c.swrkSk + _, err := cln.Write(reqB) + if err != nil { + return nil, 0, err + } + + respB := make([]byte, 2*4096) + n, err := cln.Read(respB) + if err != nil { + return nil, 0, err + } + + return respB, n, nil +} + +func (c *Criu) doSwrk(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy Notify) error { + resp, err := c.doSwrkWithResp(reqType, opts, nfy) + if err != nil { + return err + } + respType := resp.GetType() + if respType != reqType { + return errors.New("unexpected responce") + } + + return nil +} + +func (c *Criu) doSwrkWithResp(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy Notify) (*rpc.CriuResp, error) { + var resp *rpc.CriuResp + + req := rpc.CriuReq{ + Type: &reqType, + Opts: opts, + } + + if nfy != nil { + opts.NotifyScripts = proto.Bool(true) + } + + if c.swrkCmd == nil { + err := c.Prepare() + if err != nil { + return nil, err + } + + defer c.Cleanup() + } + + for { + reqB, err := proto.Marshal(&req) + if err != nil { + return nil, err + } + + respB, respS, err := c.sendAndRecv(reqB) + if err != nil { + return nil, err + } + + resp = &rpc.CriuResp{} + err = proto.Unmarshal(respB[:respS], resp) + if err != nil { + return nil, err + } + + if !resp.GetSuccess() { + return resp, fmt.Errorf("operation failed (msg:%s err:%d)", + resp.GetCrErrmsg(), resp.GetCrErrno()) + } + + respType := resp.GetType() + if respType != rpc.CriuReqType_NOTIFY { + break + } + if nfy == nil { + return resp, errors.New("unexpected notify") + } + + notify := resp.GetNotify() + switch notify.GetScript() { + case "pre-dump": + err = nfy.PreDump() + case "post-dump": + err = nfy.PostDump() + case "pre-restore": + err = nfy.PreRestore() + case "post-restore": + err = nfy.PostRestore(notify.GetPid()) + case "network-lock": + err = nfy.NetworkLock() + case "network-unlock": + err = nfy.NetworkUnlock() + case "setup-namespaces": + err = nfy.SetupNamespaces(notify.GetPid()) + case "post-setup-namespaces": + err = nfy.PostSetupNamespaces() + case "post-resume": + err = nfy.PostResume() + default: + err = nil + } + + if err != nil { + return resp, err + } + + req = rpc.CriuReq{ + Type: &respType, + NotifySuccess: proto.Bool(true), + } + } + + return resp, nil +} + +// Dump dumps a process +func (c *Criu) Dump(opts rpc.CriuOpts, nfy Notify) error { + return c.doSwrk(rpc.CriuReqType_DUMP, &opts, nfy) +} + +// Restore restores a process +func (c *Criu) Restore(opts rpc.CriuOpts, nfy Notify) error { + return c.doSwrk(rpc.CriuReqType_RESTORE, &opts, nfy) +} + +// PreDump does a pre-dump +func (c *Criu) PreDump(opts rpc.CriuOpts, nfy Notify) error { + return c.doSwrk(rpc.CriuReqType_PRE_DUMP, &opts, nfy) +} + +// StartPageServer starts the page server +func (c *Criu) StartPageServer(opts rpc.CriuOpts) error { + return c.doSwrk(rpc.CriuReqType_PAGE_SERVER, &opts, nil) +} + +// StartPageServerChld starts the page server and returns PID and port +func (c *Criu) StartPageServerChld(opts rpc.CriuOpts) (int, int, error) { + resp, err := c.doSwrkWithResp(rpc.CriuReqType_PAGE_SERVER_CHLD, &opts, nil) + if err != nil { + return 0, 0, err + } + + return int(resp.Ps.GetPid()), int(resp.Ps.GetPort()), nil +} + +// GetCriuVersion executes the VERSION RPC call and returns the version +// as an integer. Major * 10000 + Minor * 100 + SubLevel +func (c *Criu) GetCriuVersion() (int, error) { + resp, err := c.doSwrkWithResp(rpc.CriuReqType_VERSION, nil, nil) + if err != nil { + return 0, err + } + + if resp.GetType() != rpc.CriuReqType_VERSION { + return 0, fmt.Errorf("Unexpected CRIU RPC response") + } + + version := int(*resp.GetVersion().MajorNumber) * 10000 + version += int(*resp.GetVersion().MinorNumber) * 100 + if resp.GetVersion().Sublevel != nil { + version += int(*resp.GetVersion().Sublevel) + } + + if resp.GetVersion().Gitid != nil { + // taken from runc: if it is a git release -> increase minor by 1 + version -= (version % 100) + version += 100 + } + + return version, nil +} + +// IsCriuAtLeast checks if the version is at least the same +// as the parameter version +func (c *Criu) IsCriuAtLeast(version int) (bool, error) { + criuVersion, err := c.GetCriuVersion() + if err != nil { + return false, err + } + + if criuVersion >= version { + return true, nil + } + + return false, nil +} diff --git a/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/notify.go b/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/notify.go new file mode 100644 index 000000000000..1c8547b435ae --- /dev/null +++ b/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/notify.go @@ -0,0 +1,63 @@ +package criu + +//Notify interface +type Notify interface { + PreDump() error + PostDump() error + PreRestore() error + PostRestore(pid int32) error + NetworkLock() error + NetworkUnlock() error + SetupNamespaces(pid int32) error + PostSetupNamespaces() error + PostResume() error +} + +// NoNotify struct +type NoNotify struct { +} + +// PreDump NoNotify +func (c NoNotify) PreDump() error { + return nil +} + +// PostDump NoNotify +func (c NoNotify) PostDump() error { + return nil +} + +// PreRestore NoNotify +func (c NoNotify) PreRestore() error { + return nil +} + +// PostRestore NoNotify +func (c NoNotify) PostRestore(pid int32) error { + return nil +} + +// NetworkLock NoNotify +func (c NoNotify) NetworkLock() error { + return nil +} + +// NetworkUnlock NoNotify +func (c NoNotify) NetworkUnlock() error { + return nil +} + +// SetupNamespaces NoNotify +func (c NoNotify) SetupNamespaces(pid int32) error { + return nil +} + +// PostSetupNamespaces NoNotify +func (c NoNotify) PostSetupNamespaces() error { + return nil +} + +// PostResume NoNotify +func (c NoNotify) PostResume() error { + return nil +} diff --git a/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/rpc/rpc.pb.go b/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/rpc/rpc.pb.go new file mode 100644 index 000000000000..f9baece4edbf --- /dev/null +++ b/src/runtime/vendor/github.com/checkpoint-restore/go-criu/v4/rpc/rpc.pb.go @@ -0,0 +1,1667 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: rpc/rpc.proto + +package rpc + +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +type CriuCgMode int32 + +const ( + CriuCgMode_IGNORE CriuCgMode = 0 + CriuCgMode_CG_NONE CriuCgMode = 1 + CriuCgMode_PROPS CriuCgMode = 2 + CriuCgMode_SOFT CriuCgMode = 3 + CriuCgMode_FULL CriuCgMode = 4 + CriuCgMode_STRICT CriuCgMode = 5 + CriuCgMode_DEFAULT CriuCgMode = 6 +) + +var CriuCgMode_name = map[int32]string{ + 0: "IGNORE", + 1: "CG_NONE", + 2: "PROPS", + 3: "SOFT", + 4: "FULL", + 5: "STRICT", + 6: "DEFAULT", +} + +var CriuCgMode_value = map[string]int32{ + "IGNORE": 0, + "CG_NONE": 1, + "PROPS": 2, + "SOFT": 3, + "FULL": 4, + "STRICT": 5, + "DEFAULT": 6, +} + +func (x CriuCgMode) Enum() *CriuCgMode { + p := new(CriuCgMode) + *p = x + return p +} + +func (x CriuCgMode) String() string { + return proto.EnumName(CriuCgMode_name, int32(x)) +} + +func (x *CriuCgMode) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(CriuCgMode_value, data, "CriuCgMode") + if err != nil { + return err + } + *x = CriuCgMode(value) + return nil +} + +func (CriuCgMode) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_d9874a201429861e, []int{0} +} + +type CriuPreDumpMode int32 + +const ( + CriuPreDumpMode_SPLICE CriuPreDumpMode = 1 + CriuPreDumpMode_VM_READ CriuPreDumpMode = 2 +) + +var CriuPreDumpMode_name = map[int32]string{ + 1: "SPLICE", + 2: "VM_READ", +} + +var CriuPreDumpMode_value = map[string]int32{ + "SPLICE": 1, + "VM_READ": 2, +} + +func (x CriuPreDumpMode) Enum() *CriuPreDumpMode { + p := new(CriuPreDumpMode) + *p = x + return p +} + +func (x CriuPreDumpMode) String() string { + return proto.EnumName(CriuPreDumpMode_name, int32(x)) +} + +func (x *CriuPreDumpMode) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(CriuPreDumpMode_value, data, "CriuPreDumpMode") + if err != nil { + return err + } + *x = CriuPreDumpMode(value) + return nil +} + +func (CriuPreDumpMode) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_d9874a201429861e, []int{1} +} + +type CriuReqType int32 + +const ( + CriuReqType_EMPTY CriuReqType = 0 + CriuReqType_DUMP CriuReqType = 1 + CriuReqType_RESTORE CriuReqType = 2 + CriuReqType_CHECK CriuReqType = 3 + CriuReqType_PRE_DUMP CriuReqType = 4 + CriuReqType_PAGE_SERVER CriuReqType = 5 + CriuReqType_NOTIFY CriuReqType = 6 + CriuReqType_CPUINFO_DUMP CriuReqType = 7 + CriuReqType_CPUINFO_CHECK CriuReqType = 8 + CriuReqType_FEATURE_CHECK CriuReqType = 9 + CriuReqType_VERSION CriuReqType = 10 + CriuReqType_WAIT_PID CriuReqType = 11 + CriuReqType_PAGE_SERVER_CHLD CriuReqType = 12 +) + +var CriuReqType_name = map[int32]string{ + 0: "EMPTY", + 1: "DUMP", + 2: "RESTORE", + 3: "CHECK", + 4: "PRE_DUMP", + 5: "PAGE_SERVER", + 6: "NOTIFY", + 7: "CPUINFO_DUMP", + 8: "CPUINFO_CHECK", + 9: "FEATURE_CHECK", + 10: "VERSION", + 11: "WAIT_PID", + 12: "PAGE_SERVER_CHLD", +} + +var CriuReqType_value = map[string]int32{ + "EMPTY": 0, + "DUMP": 1, + "RESTORE": 2, + "CHECK": 3, + "PRE_DUMP": 4, + "PAGE_SERVER": 5, + "NOTIFY": 6, + "CPUINFO_DUMP": 7, + "CPUINFO_CHECK": 8, + "FEATURE_CHECK": 9, + "VERSION": 10, + "WAIT_PID": 11, + "PAGE_SERVER_CHLD": 12, +} + +func (x CriuReqType) Enum() *CriuReqType { + p := new(CriuReqType) + *p = x + return p +} + +func (x CriuReqType) String() string { + return proto.EnumName(CriuReqType_name, int32(x)) +} + +func (x *CriuReqType) UnmarshalJSON(data []byte) error { + value, err := proto.UnmarshalJSONEnum(CriuReqType_value, data, "CriuReqType") + if err != nil { + return err + } + *x = CriuReqType(value) + return nil +} + +func (CriuReqType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_d9874a201429861e, []int{2} +} + +type CriuPageServerInfo struct { + Address *string `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` + Port *int32 `protobuf:"varint,2,opt,name=port" json:"port,omitempty"` + Pid *int32 `protobuf:"varint,3,opt,name=pid" json:"pid,omitempty"` + Fd *int32 `protobuf:"varint,4,opt,name=fd" json:"fd,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CriuPageServerInfo) Reset() { *m = CriuPageServerInfo{} } +func (m *CriuPageServerInfo) String() string { return proto.CompactTextString(m) } +func (*CriuPageServerInfo) ProtoMessage() {} +func (*CriuPageServerInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_d9874a201429861e, []int{0} +} + +func (m *CriuPageServerInfo) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CriuPageServerInfo.Unmarshal(m, b) +} +func (m *CriuPageServerInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CriuPageServerInfo.Marshal(b, m, deterministic) +} +func (m *CriuPageServerInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_CriuPageServerInfo.Merge(m, src) +} +func (m *CriuPageServerInfo) XXX_Size() int { + return xxx_messageInfo_CriuPageServerInfo.Size(m) +} +func (m *CriuPageServerInfo) XXX_DiscardUnknown() { + xxx_messageInfo_CriuPageServerInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_CriuPageServerInfo proto.InternalMessageInfo + +func (m *CriuPageServerInfo) GetAddress() string { + if m != nil && m.Address != nil { + return *m.Address + } + return "" +} + +func (m *CriuPageServerInfo) GetPort() int32 { + if m != nil && m.Port != nil { + return *m.Port + } + return 0 +} + +func (m *CriuPageServerInfo) GetPid() int32 { + if m != nil && m.Pid != nil { + return *m.Pid + } + return 0 +} + +func (m *CriuPageServerInfo) GetFd() int32 { + if m != nil && m.Fd != nil { + return *m.Fd + } + return 0 +} + +type CriuVethPair struct { + IfIn *string `protobuf:"bytes,1,req,name=if_in,json=ifIn" json:"if_in,omitempty"` + IfOut *string `protobuf:"bytes,2,req,name=if_out,json=ifOut" json:"if_out,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CriuVethPair) Reset() { *m = CriuVethPair{} } +func (m *CriuVethPair) String() string { return proto.CompactTextString(m) } +func (*CriuVethPair) ProtoMessage() {} +func (*CriuVethPair) Descriptor() ([]byte, []int) { + return fileDescriptor_d9874a201429861e, []int{1} +} + +func (m *CriuVethPair) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CriuVethPair.Unmarshal(m, b) +} +func (m *CriuVethPair) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CriuVethPair.Marshal(b, m, deterministic) +} +func (m *CriuVethPair) XXX_Merge(src proto.Message) { + xxx_messageInfo_CriuVethPair.Merge(m, src) +} +func (m *CriuVethPair) XXX_Size() int { + return xxx_messageInfo_CriuVethPair.Size(m) +} +func (m *CriuVethPair) XXX_DiscardUnknown() { + xxx_messageInfo_CriuVethPair.DiscardUnknown(m) +} + +var xxx_messageInfo_CriuVethPair proto.InternalMessageInfo + +func (m *CriuVethPair) GetIfIn() string { + if m != nil && m.IfIn != nil { + return *m.IfIn + } + return "" +} + +func (m *CriuVethPair) GetIfOut() string { + if m != nil && m.IfOut != nil { + return *m.IfOut + } + return "" +} + +type ExtMountMap struct { + Key *string `protobuf:"bytes,1,req,name=key" json:"key,omitempty"` + Val *string `protobuf:"bytes,2,req,name=val" json:"val,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ExtMountMap) Reset() { *m = ExtMountMap{} } +func (m *ExtMountMap) String() string { return proto.CompactTextString(m) } +func (*ExtMountMap) ProtoMessage() {} +func (*ExtMountMap) Descriptor() ([]byte, []int) { + return fileDescriptor_d9874a201429861e, []int{2} +} + +func (m *ExtMountMap) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ExtMountMap.Unmarshal(m, b) +} +func (m *ExtMountMap) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ExtMountMap.Marshal(b, m, deterministic) +} +func (m *ExtMountMap) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExtMountMap.Merge(m, src) +} +func (m *ExtMountMap) XXX_Size() int { + return xxx_messageInfo_ExtMountMap.Size(m) +} +func (m *ExtMountMap) XXX_DiscardUnknown() { + xxx_messageInfo_ExtMountMap.DiscardUnknown(m) +} + +var xxx_messageInfo_ExtMountMap proto.InternalMessageInfo + +func (m *ExtMountMap) GetKey() string { + if m != nil && m.Key != nil { + return *m.Key + } + return "" +} + +func (m *ExtMountMap) GetVal() string { + if m != nil && m.Val != nil { + return *m.Val + } + return "" +} + +type JoinNamespace struct { + Ns *string `protobuf:"bytes,1,req,name=ns" json:"ns,omitempty"` + NsFile *string `protobuf:"bytes,2,req,name=ns_file,json=nsFile" json:"ns_file,omitempty"` + ExtraOpt *string `protobuf:"bytes,3,opt,name=extra_opt,json=extraOpt" json:"extra_opt,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *JoinNamespace) Reset() { *m = JoinNamespace{} } +func (m *JoinNamespace) String() string { return proto.CompactTextString(m) } +func (*JoinNamespace) ProtoMessage() {} +func (*JoinNamespace) Descriptor() ([]byte, []int) { + return fileDescriptor_d9874a201429861e, []int{3} +} + +func (m *JoinNamespace) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_JoinNamespace.Unmarshal(m, b) +} +func (m *JoinNamespace) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_JoinNamespace.Marshal(b, m, deterministic) +} +func (m *JoinNamespace) XXX_Merge(src proto.Message) { + xxx_messageInfo_JoinNamespace.Merge(m, src) +} +func (m *JoinNamespace) XXX_Size() int { + return xxx_messageInfo_JoinNamespace.Size(m) +} +func (m *JoinNamespace) XXX_DiscardUnknown() { + xxx_messageInfo_JoinNamespace.DiscardUnknown(m) +} + +var xxx_messageInfo_JoinNamespace proto.InternalMessageInfo + +func (m *JoinNamespace) GetNs() string { + if m != nil && m.Ns != nil { + return *m.Ns + } + return "" +} + +func (m *JoinNamespace) GetNsFile() string { + if m != nil && m.NsFile != nil { + return *m.NsFile + } + return "" +} + +func (m *JoinNamespace) GetExtraOpt() string { + if m != nil && m.ExtraOpt != nil { + return *m.ExtraOpt + } + return "" +} + +type InheritFd struct { + Key *string `protobuf:"bytes,1,req,name=key" json:"key,omitempty"` + Fd *int32 `protobuf:"varint,2,req,name=fd" json:"fd,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *InheritFd) Reset() { *m = InheritFd{} } +func (m *InheritFd) String() string { return proto.CompactTextString(m) } +func (*InheritFd) ProtoMessage() {} +func (*InheritFd) Descriptor() ([]byte, []int) { + return fileDescriptor_d9874a201429861e, []int{4} +} + +func (m *InheritFd) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_InheritFd.Unmarshal(m, b) +} +func (m *InheritFd) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_InheritFd.Marshal(b, m, deterministic) +} +func (m *InheritFd) XXX_Merge(src proto.Message) { + xxx_messageInfo_InheritFd.Merge(m, src) +} +func (m *InheritFd) XXX_Size() int { + return xxx_messageInfo_InheritFd.Size(m) +} +func (m *InheritFd) XXX_DiscardUnknown() { + xxx_messageInfo_InheritFd.DiscardUnknown(m) +} + +var xxx_messageInfo_InheritFd proto.InternalMessageInfo + +func (m *InheritFd) GetKey() string { + if m != nil && m.Key != nil { + return *m.Key + } + return "" +} + +func (m *InheritFd) GetFd() int32 { + if m != nil && m.Fd != nil { + return *m.Fd + } + return 0 +} + +type CgroupRoot struct { + Ctrl *string `protobuf:"bytes,1,opt,name=ctrl" json:"ctrl,omitempty"` + Path *string `protobuf:"bytes,2,req,name=path" json:"path,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CgroupRoot) Reset() { *m = CgroupRoot{} } +func (m *CgroupRoot) String() string { return proto.CompactTextString(m) } +func (*CgroupRoot) ProtoMessage() {} +func (*CgroupRoot) Descriptor() ([]byte, []int) { + return fileDescriptor_d9874a201429861e, []int{5} +} + +func (m *CgroupRoot) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CgroupRoot.Unmarshal(m, b) +} +func (m *CgroupRoot) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CgroupRoot.Marshal(b, m, deterministic) +} +func (m *CgroupRoot) XXX_Merge(src proto.Message) { + xxx_messageInfo_CgroupRoot.Merge(m, src) +} +func (m *CgroupRoot) XXX_Size() int { + return xxx_messageInfo_CgroupRoot.Size(m) +} +func (m *CgroupRoot) XXX_DiscardUnknown() { + xxx_messageInfo_CgroupRoot.DiscardUnknown(m) +} + +var xxx_messageInfo_CgroupRoot proto.InternalMessageInfo + +func (m *CgroupRoot) GetCtrl() string { + if m != nil && m.Ctrl != nil { + return *m.Ctrl + } + return "" +} + +func (m *CgroupRoot) GetPath() string { + if m != nil && m.Path != nil { + return *m.Path + } + return "" +} + +type UnixSk struct { + Inode *uint32 `protobuf:"varint,1,req,name=inode" json:"inode,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UnixSk) Reset() { *m = UnixSk{} } +func (m *UnixSk) String() string { return proto.CompactTextString(m) } +func (*UnixSk) ProtoMessage() {} +func (*UnixSk) Descriptor() ([]byte, []int) { + return fileDescriptor_d9874a201429861e, []int{6} +} + +func (m *UnixSk) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UnixSk.Unmarshal(m, b) +} +func (m *UnixSk) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UnixSk.Marshal(b, m, deterministic) +} +func (m *UnixSk) XXX_Merge(src proto.Message) { + xxx_messageInfo_UnixSk.Merge(m, src) +} +func (m *UnixSk) XXX_Size() int { + return xxx_messageInfo_UnixSk.Size(m) +} +func (m *UnixSk) XXX_DiscardUnknown() { + xxx_messageInfo_UnixSk.DiscardUnknown(m) +} + +var xxx_messageInfo_UnixSk proto.InternalMessageInfo + +func (m *UnixSk) GetInode() uint32 { + if m != nil && m.Inode != nil { + return *m.Inode + } + return 0 +} + +type CriuOpts struct { + ImagesDirFd *int32 `protobuf:"varint,1,req,name=images_dir_fd,json=imagesDirFd" json:"images_dir_fd,omitempty"` + Pid *int32 `protobuf:"varint,2,opt,name=pid" json:"pid,omitempty"` + LeaveRunning *bool `protobuf:"varint,3,opt,name=leave_running,json=leaveRunning" json:"leave_running,omitempty"` + ExtUnixSk *bool `protobuf:"varint,4,opt,name=ext_unix_sk,json=extUnixSk" json:"ext_unix_sk,omitempty"` + TcpEstablished *bool `protobuf:"varint,5,opt,name=tcp_established,json=tcpEstablished" json:"tcp_established,omitempty"` + EvasiveDevices *bool `protobuf:"varint,6,opt,name=evasive_devices,json=evasiveDevices" json:"evasive_devices,omitempty"` + ShellJob *bool `protobuf:"varint,7,opt,name=shell_job,json=shellJob" json:"shell_job,omitempty"` + FileLocks *bool `protobuf:"varint,8,opt,name=file_locks,json=fileLocks" json:"file_locks,omitempty"` + LogLevel *int32 `protobuf:"varint,9,opt,name=log_level,json=logLevel,def=2" json:"log_level,omitempty"` + LogFile *string `protobuf:"bytes,10,opt,name=log_file,json=logFile" json:"log_file,omitempty"` + Ps *CriuPageServerInfo `protobuf:"bytes,11,opt,name=ps" json:"ps,omitempty"` + NotifyScripts *bool `protobuf:"varint,12,opt,name=notify_scripts,json=notifyScripts" json:"notify_scripts,omitempty"` + Root *string `protobuf:"bytes,13,opt,name=root" json:"root,omitempty"` + ParentImg *string `protobuf:"bytes,14,opt,name=parent_img,json=parentImg" json:"parent_img,omitempty"` + TrackMem *bool `protobuf:"varint,15,opt,name=track_mem,json=trackMem" json:"track_mem,omitempty"` + AutoDedup *bool `protobuf:"varint,16,opt,name=auto_dedup,json=autoDedup" json:"auto_dedup,omitempty"` + WorkDirFd *int32 `protobuf:"varint,17,opt,name=work_dir_fd,json=workDirFd" json:"work_dir_fd,omitempty"` + LinkRemap *bool `protobuf:"varint,18,opt,name=link_remap,json=linkRemap" json:"link_remap,omitempty"` + Veths []*CriuVethPair `protobuf:"bytes,19,rep,name=veths" json:"veths,omitempty"` + CpuCap *uint32 `protobuf:"varint,20,opt,name=cpu_cap,json=cpuCap,def=4294967295" json:"cpu_cap,omitempty"` + ForceIrmap *bool `protobuf:"varint,21,opt,name=force_irmap,json=forceIrmap" json:"force_irmap,omitempty"` + ExecCmd []string `protobuf:"bytes,22,rep,name=exec_cmd,json=execCmd" json:"exec_cmd,omitempty"` + ExtMnt []*ExtMountMap `protobuf:"bytes,23,rep,name=ext_mnt,json=extMnt" json:"ext_mnt,omitempty"` + ManageCgroups *bool `protobuf:"varint,24,opt,name=manage_cgroups,json=manageCgroups" json:"manage_cgroups,omitempty"` + CgRoot []*CgroupRoot `protobuf:"bytes,25,rep,name=cg_root,json=cgRoot" json:"cg_root,omitempty"` + RstSibling *bool `protobuf:"varint,26,opt,name=rst_sibling,json=rstSibling" json:"rst_sibling,omitempty"` + InheritFd []*InheritFd `protobuf:"bytes,27,rep,name=inherit_fd,json=inheritFd" json:"inherit_fd,omitempty"` + AutoExtMnt *bool `protobuf:"varint,28,opt,name=auto_ext_mnt,json=autoExtMnt" json:"auto_ext_mnt,omitempty"` + ExtSharing *bool `protobuf:"varint,29,opt,name=ext_sharing,json=extSharing" json:"ext_sharing,omitempty"` + ExtMasters *bool `protobuf:"varint,30,opt,name=ext_masters,json=extMasters" json:"ext_masters,omitempty"` + SkipMnt []string `protobuf:"bytes,31,rep,name=skip_mnt,json=skipMnt" json:"skip_mnt,omitempty"` + EnableFs []string `protobuf:"bytes,32,rep,name=enable_fs,json=enableFs" json:"enable_fs,omitempty"` + UnixSkIno []*UnixSk `protobuf:"bytes,33,rep,name=unix_sk_ino,json=unixSkIno" json:"unix_sk_ino,omitempty"` + ManageCgroupsMode *CriuCgMode `protobuf:"varint,34,opt,name=manage_cgroups_mode,json=manageCgroupsMode,enum=CriuCgMode" json:"manage_cgroups_mode,omitempty"` + GhostLimit *uint32 `protobuf:"varint,35,opt,name=ghost_limit,json=ghostLimit,def=1048576" json:"ghost_limit,omitempty"` + IrmapScanPaths []string `protobuf:"bytes,36,rep,name=irmap_scan_paths,json=irmapScanPaths" json:"irmap_scan_paths,omitempty"` + External []string `protobuf:"bytes,37,rep,name=external" json:"external,omitempty"` + EmptyNs *uint32 `protobuf:"varint,38,opt,name=empty_ns,json=emptyNs" json:"empty_ns,omitempty"` + JoinNs []*JoinNamespace `protobuf:"bytes,39,rep,name=join_ns,json=joinNs" json:"join_ns,omitempty"` + CgroupProps *string `protobuf:"bytes,41,opt,name=cgroup_props,json=cgroupProps" json:"cgroup_props,omitempty"` + CgroupPropsFile *string `protobuf:"bytes,42,opt,name=cgroup_props_file,json=cgroupPropsFile" json:"cgroup_props_file,omitempty"` + CgroupDumpController []string `protobuf:"bytes,43,rep,name=cgroup_dump_controller,json=cgroupDumpController" json:"cgroup_dump_controller,omitempty"` + FreezeCgroup *string `protobuf:"bytes,44,opt,name=freeze_cgroup,json=freezeCgroup" json:"freeze_cgroup,omitempty"` + Timeout *uint32 `protobuf:"varint,45,opt,name=timeout" json:"timeout,omitempty"` + TcpSkipInFlight *bool `protobuf:"varint,46,opt,name=tcp_skip_in_flight,json=tcpSkipInFlight" json:"tcp_skip_in_flight,omitempty"` + WeakSysctls *bool `protobuf:"varint,47,opt,name=weak_sysctls,json=weakSysctls" json:"weak_sysctls,omitempty"` + LazyPages *bool `protobuf:"varint,48,opt,name=lazy_pages,json=lazyPages" json:"lazy_pages,omitempty"` + StatusFd *int32 `protobuf:"varint,49,opt,name=status_fd,json=statusFd" json:"status_fd,omitempty"` + OrphanPtsMaster *bool `protobuf:"varint,50,opt,name=orphan_pts_master,json=orphanPtsMaster" json:"orphan_pts_master,omitempty"` + ConfigFile *string `protobuf:"bytes,51,opt,name=config_file,json=configFile" json:"config_file,omitempty"` + TcpClose *bool `protobuf:"varint,52,opt,name=tcp_close,json=tcpClose" json:"tcp_close,omitempty"` + LsmProfile *string `protobuf:"bytes,53,opt,name=lsm_profile,json=lsmProfile" json:"lsm_profile,omitempty"` + TlsCacert *string `protobuf:"bytes,54,opt,name=tls_cacert,json=tlsCacert" json:"tls_cacert,omitempty"` + TlsCacrl *string `protobuf:"bytes,55,opt,name=tls_cacrl,json=tlsCacrl" json:"tls_cacrl,omitempty"` + TlsCert *string `protobuf:"bytes,56,opt,name=tls_cert,json=tlsCert" json:"tls_cert,omitempty"` + TlsKey *string `protobuf:"bytes,57,opt,name=tls_key,json=tlsKey" json:"tls_key,omitempty"` + Tls *bool `protobuf:"varint,58,opt,name=tls" json:"tls,omitempty"` + TlsNoCnVerify *bool `protobuf:"varint,59,opt,name=tls_no_cn_verify,json=tlsNoCnVerify" json:"tls_no_cn_verify,omitempty"` + CgroupYard *string `protobuf:"bytes,60,opt,name=cgroup_yard,json=cgroupYard" json:"cgroup_yard,omitempty"` + PreDumpMode *CriuPreDumpMode `protobuf:"varint,61,opt,name=pre_dump_mode,json=preDumpMode,enum=CriuPreDumpMode,def=1" json:"pre_dump_mode,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CriuOpts) Reset() { *m = CriuOpts{} } +func (m *CriuOpts) String() string { return proto.CompactTextString(m) } +func (*CriuOpts) ProtoMessage() {} +func (*CriuOpts) Descriptor() ([]byte, []int) { + return fileDescriptor_d9874a201429861e, []int{7} +} + +func (m *CriuOpts) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CriuOpts.Unmarshal(m, b) +} +func (m *CriuOpts) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CriuOpts.Marshal(b, m, deterministic) +} +func (m *CriuOpts) XXX_Merge(src proto.Message) { + xxx_messageInfo_CriuOpts.Merge(m, src) +} +func (m *CriuOpts) XXX_Size() int { + return xxx_messageInfo_CriuOpts.Size(m) +} +func (m *CriuOpts) XXX_DiscardUnknown() { + xxx_messageInfo_CriuOpts.DiscardUnknown(m) +} + +var xxx_messageInfo_CriuOpts proto.InternalMessageInfo + +const Default_CriuOpts_LogLevel int32 = 2 +const Default_CriuOpts_CpuCap uint32 = 4294967295 +const Default_CriuOpts_GhostLimit uint32 = 1048576 +const Default_CriuOpts_PreDumpMode CriuPreDumpMode = CriuPreDumpMode_SPLICE + +func (m *CriuOpts) GetImagesDirFd() int32 { + if m != nil && m.ImagesDirFd != nil { + return *m.ImagesDirFd + } + return 0 +} + +func (m *CriuOpts) GetPid() int32 { + if m != nil && m.Pid != nil { + return *m.Pid + } + return 0 +} + +func (m *CriuOpts) GetLeaveRunning() bool { + if m != nil && m.LeaveRunning != nil { + return *m.LeaveRunning + } + return false +} + +func (m *CriuOpts) GetExtUnixSk() bool { + if m != nil && m.ExtUnixSk != nil { + return *m.ExtUnixSk + } + return false +} + +func (m *CriuOpts) GetTcpEstablished() bool { + if m != nil && m.TcpEstablished != nil { + return *m.TcpEstablished + } + return false +} + +func (m *CriuOpts) GetEvasiveDevices() bool { + if m != nil && m.EvasiveDevices != nil { + return *m.EvasiveDevices + } + return false +} + +func (m *CriuOpts) GetShellJob() bool { + if m != nil && m.ShellJob != nil { + return *m.ShellJob + } + return false +} + +func (m *CriuOpts) GetFileLocks() bool { + if m != nil && m.FileLocks != nil { + return *m.FileLocks + } + return false +} + +func (m *CriuOpts) GetLogLevel() int32 { + if m != nil && m.LogLevel != nil { + return *m.LogLevel + } + return Default_CriuOpts_LogLevel +} + +func (m *CriuOpts) GetLogFile() string { + if m != nil && m.LogFile != nil { + return *m.LogFile + } + return "" +} + +func (m *CriuOpts) GetPs() *CriuPageServerInfo { + if m != nil { + return m.Ps + } + return nil +} + +func (m *CriuOpts) GetNotifyScripts() bool { + if m != nil && m.NotifyScripts != nil { + return *m.NotifyScripts + } + return false +} + +func (m *CriuOpts) GetRoot() string { + if m != nil && m.Root != nil { + return *m.Root + } + return "" +} + +func (m *CriuOpts) GetParentImg() string { + if m != nil && m.ParentImg != nil { + return *m.ParentImg + } + return "" +} + +func (m *CriuOpts) GetTrackMem() bool { + if m != nil && m.TrackMem != nil { + return *m.TrackMem + } + return false +} + +func (m *CriuOpts) GetAutoDedup() bool { + if m != nil && m.AutoDedup != nil { + return *m.AutoDedup + } + return false +} + +func (m *CriuOpts) GetWorkDirFd() int32 { + if m != nil && m.WorkDirFd != nil { + return *m.WorkDirFd + } + return 0 +} + +func (m *CriuOpts) GetLinkRemap() bool { + if m != nil && m.LinkRemap != nil { + return *m.LinkRemap + } + return false +} + +func (m *CriuOpts) GetVeths() []*CriuVethPair { + if m != nil { + return m.Veths + } + return nil +} + +func (m *CriuOpts) GetCpuCap() uint32 { + if m != nil && m.CpuCap != nil { + return *m.CpuCap + } + return Default_CriuOpts_CpuCap +} + +func (m *CriuOpts) GetForceIrmap() bool { + if m != nil && m.ForceIrmap != nil { + return *m.ForceIrmap + } + return false +} + +func (m *CriuOpts) GetExecCmd() []string { + if m != nil { + return m.ExecCmd + } + return nil +} + +func (m *CriuOpts) GetExtMnt() []*ExtMountMap { + if m != nil { + return m.ExtMnt + } + return nil +} + +func (m *CriuOpts) GetManageCgroups() bool { + if m != nil && m.ManageCgroups != nil { + return *m.ManageCgroups + } + return false +} + +func (m *CriuOpts) GetCgRoot() []*CgroupRoot { + if m != nil { + return m.CgRoot + } + return nil +} + +func (m *CriuOpts) GetRstSibling() bool { + if m != nil && m.RstSibling != nil { + return *m.RstSibling + } + return false +} + +func (m *CriuOpts) GetInheritFd() []*InheritFd { + if m != nil { + return m.InheritFd + } + return nil +} + +func (m *CriuOpts) GetAutoExtMnt() bool { + if m != nil && m.AutoExtMnt != nil { + return *m.AutoExtMnt + } + return false +} + +func (m *CriuOpts) GetExtSharing() bool { + if m != nil && m.ExtSharing != nil { + return *m.ExtSharing + } + return false +} + +func (m *CriuOpts) GetExtMasters() bool { + if m != nil && m.ExtMasters != nil { + return *m.ExtMasters + } + return false +} + +func (m *CriuOpts) GetSkipMnt() []string { + if m != nil { + return m.SkipMnt + } + return nil +} + +func (m *CriuOpts) GetEnableFs() []string { + if m != nil { + return m.EnableFs + } + return nil +} + +func (m *CriuOpts) GetUnixSkIno() []*UnixSk { + if m != nil { + return m.UnixSkIno + } + return nil +} + +func (m *CriuOpts) GetManageCgroupsMode() CriuCgMode { + if m != nil && m.ManageCgroupsMode != nil { + return *m.ManageCgroupsMode + } + return CriuCgMode_IGNORE +} + +func (m *CriuOpts) GetGhostLimit() uint32 { + if m != nil && m.GhostLimit != nil { + return *m.GhostLimit + } + return Default_CriuOpts_GhostLimit +} + +func (m *CriuOpts) GetIrmapScanPaths() []string { + if m != nil { + return m.IrmapScanPaths + } + return nil +} + +func (m *CriuOpts) GetExternal() []string { + if m != nil { + return m.External + } + return nil +} + +func (m *CriuOpts) GetEmptyNs() uint32 { + if m != nil && m.EmptyNs != nil { + return *m.EmptyNs + } + return 0 +} + +func (m *CriuOpts) GetJoinNs() []*JoinNamespace { + if m != nil { + return m.JoinNs + } + return nil +} + +func (m *CriuOpts) GetCgroupProps() string { + if m != nil && m.CgroupProps != nil { + return *m.CgroupProps + } + return "" +} + +func (m *CriuOpts) GetCgroupPropsFile() string { + if m != nil && m.CgroupPropsFile != nil { + return *m.CgroupPropsFile + } + return "" +} + +func (m *CriuOpts) GetCgroupDumpController() []string { + if m != nil { + return m.CgroupDumpController + } + return nil +} + +func (m *CriuOpts) GetFreezeCgroup() string { + if m != nil && m.FreezeCgroup != nil { + return *m.FreezeCgroup + } + return "" +} + +func (m *CriuOpts) GetTimeout() uint32 { + if m != nil && m.Timeout != nil { + return *m.Timeout + } + return 0 +} + +func (m *CriuOpts) GetTcpSkipInFlight() bool { + if m != nil && m.TcpSkipInFlight != nil { + return *m.TcpSkipInFlight + } + return false +} + +func (m *CriuOpts) GetWeakSysctls() bool { + if m != nil && m.WeakSysctls != nil { + return *m.WeakSysctls + } + return false +} + +func (m *CriuOpts) GetLazyPages() bool { + if m != nil && m.LazyPages != nil { + return *m.LazyPages + } + return false +} + +func (m *CriuOpts) GetStatusFd() int32 { + if m != nil && m.StatusFd != nil { + return *m.StatusFd + } + return 0 +} + +func (m *CriuOpts) GetOrphanPtsMaster() bool { + if m != nil && m.OrphanPtsMaster != nil { + return *m.OrphanPtsMaster + } + return false +} + +func (m *CriuOpts) GetConfigFile() string { + if m != nil && m.ConfigFile != nil { + return *m.ConfigFile + } + return "" +} + +func (m *CriuOpts) GetTcpClose() bool { + if m != nil && m.TcpClose != nil { + return *m.TcpClose + } + return false +} + +func (m *CriuOpts) GetLsmProfile() string { + if m != nil && m.LsmProfile != nil { + return *m.LsmProfile + } + return "" +} + +func (m *CriuOpts) GetTlsCacert() string { + if m != nil && m.TlsCacert != nil { + return *m.TlsCacert + } + return "" +} + +func (m *CriuOpts) GetTlsCacrl() string { + if m != nil && m.TlsCacrl != nil { + return *m.TlsCacrl + } + return "" +} + +func (m *CriuOpts) GetTlsCert() string { + if m != nil && m.TlsCert != nil { + return *m.TlsCert + } + return "" +} + +func (m *CriuOpts) GetTlsKey() string { + if m != nil && m.TlsKey != nil { + return *m.TlsKey + } + return "" +} + +func (m *CriuOpts) GetTls() bool { + if m != nil && m.Tls != nil { + return *m.Tls + } + return false +} + +func (m *CriuOpts) GetTlsNoCnVerify() bool { + if m != nil && m.TlsNoCnVerify != nil { + return *m.TlsNoCnVerify + } + return false +} + +func (m *CriuOpts) GetCgroupYard() string { + if m != nil && m.CgroupYard != nil { + return *m.CgroupYard + } + return "" +} + +func (m *CriuOpts) GetPreDumpMode() CriuPreDumpMode { + if m != nil && m.PreDumpMode != nil { + return *m.PreDumpMode + } + return Default_CriuOpts_PreDumpMode +} + +type CriuDumpResp struct { + Restored *bool `protobuf:"varint,1,opt,name=restored" json:"restored,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CriuDumpResp) Reset() { *m = CriuDumpResp{} } +func (m *CriuDumpResp) String() string { return proto.CompactTextString(m) } +func (*CriuDumpResp) ProtoMessage() {} +func (*CriuDumpResp) Descriptor() ([]byte, []int) { + return fileDescriptor_d9874a201429861e, []int{8} +} + +func (m *CriuDumpResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CriuDumpResp.Unmarshal(m, b) +} +func (m *CriuDumpResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CriuDumpResp.Marshal(b, m, deterministic) +} +func (m *CriuDumpResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_CriuDumpResp.Merge(m, src) +} +func (m *CriuDumpResp) XXX_Size() int { + return xxx_messageInfo_CriuDumpResp.Size(m) +} +func (m *CriuDumpResp) XXX_DiscardUnknown() { + xxx_messageInfo_CriuDumpResp.DiscardUnknown(m) +} + +var xxx_messageInfo_CriuDumpResp proto.InternalMessageInfo + +func (m *CriuDumpResp) GetRestored() bool { + if m != nil && m.Restored != nil { + return *m.Restored + } + return false +} + +type CriuRestoreResp struct { + Pid *int32 `protobuf:"varint,1,req,name=pid" json:"pid,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CriuRestoreResp) Reset() { *m = CriuRestoreResp{} } +func (m *CriuRestoreResp) String() string { return proto.CompactTextString(m) } +func (*CriuRestoreResp) ProtoMessage() {} +func (*CriuRestoreResp) Descriptor() ([]byte, []int) { + return fileDescriptor_d9874a201429861e, []int{9} +} + +func (m *CriuRestoreResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CriuRestoreResp.Unmarshal(m, b) +} +func (m *CriuRestoreResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CriuRestoreResp.Marshal(b, m, deterministic) +} +func (m *CriuRestoreResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_CriuRestoreResp.Merge(m, src) +} +func (m *CriuRestoreResp) XXX_Size() int { + return xxx_messageInfo_CriuRestoreResp.Size(m) +} +func (m *CriuRestoreResp) XXX_DiscardUnknown() { + xxx_messageInfo_CriuRestoreResp.DiscardUnknown(m) +} + +var xxx_messageInfo_CriuRestoreResp proto.InternalMessageInfo + +func (m *CriuRestoreResp) GetPid() int32 { + if m != nil && m.Pid != nil { + return *m.Pid + } + return 0 +} + +type CriuNotify struct { + Script *string `protobuf:"bytes,1,opt,name=script" json:"script,omitempty"` + Pid *int32 `protobuf:"varint,2,opt,name=pid" json:"pid,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CriuNotify) Reset() { *m = CriuNotify{} } +func (m *CriuNotify) String() string { return proto.CompactTextString(m) } +func (*CriuNotify) ProtoMessage() {} +func (*CriuNotify) Descriptor() ([]byte, []int) { + return fileDescriptor_d9874a201429861e, []int{10} +} + +func (m *CriuNotify) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CriuNotify.Unmarshal(m, b) +} +func (m *CriuNotify) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CriuNotify.Marshal(b, m, deterministic) +} +func (m *CriuNotify) XXX_Merge(src proto.Message) { + xxx_messageInfo_CriuNotify.Merge(m, src) +} +func (m *CriuNotify) XXX_Size() int { + return xxx_messageInfo_CriuNotify.Size(m) +} +func (m *CriuNotify) XXX_DiscardUnknown() { + xxx_messageInfo_CriuNotify.DiscardUnknown(m) +} + +var xxx_messageInfo_CriuNotify proto.InternalMessageInfo + +func (m *CriuNotify) GetScript() string { + if m != nil && m.Script != nil { + return *m.Script + } + return "" +} + +func (m *CriuNotify) GetPid() int32 { + if m != nil && m.Pid != nil { + return *m.Pid + } + return 0 +} + +// +// List of features which can queried via +// CRIU_REQ_TYPE__FEATURE_CHECK +type CriuFeatures struct { + MemTrack *bool `protobuf:"varint,1,opt,name=mem_track,json=memTrack" json:"mem_track,omitempty"` + LazyPages *bool `protobuf:"varint,2,opt,name=lazy_pages,json=lazyPages" json:"lazy_pages,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CriuFeatures) Reset() { *m = CriuFeatures{} } +func (m *CriuFeatures) String() string { return proto.CompactTextString(m) } +func (*CriuFeatures) ProtoMessage() {} +func (*CriuFeatures) Descriptor() ([]byte, []int) { + return fileDescriptor_d9874a201429861e, []int{11} +} + +func (m *CriuFeatures) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CriuFeatures.Unmarshal(m, b) +} +func (m *CriuFeatures) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CriuFeatures.Marshal(b, m, deterministic) +} +func (m *CriuFeatures) XXX_Merge(src proto.Message) { + xxx_messageInfo_CriuFeatures.Merge(m, src) +} +func (m *CriuFeatures) XXX_Size() int { + return xxx_messageInfo_CriuFeatures.Size(m) +} +func (m *CriuFeatures) XXX_DiscardUnknown() { + xxx_messageInfo_CriuFeatures.DiscardUnknown(m) +} + +var xxx_messageInfo_CriuFeatures proto.InternalMessageInfo + +func (m *CriuFeatures) GetMemTrack() bool { + if m != nil && m.MemTrack != nil { + return *m.MemTrack + } + return false +} + +func (m *CriuFeatures) GetLazyPages() bool { + if m != nil && m.LazyPages != nil { + return *m.LazyPages + } + return false +} + +type CriuReq struct { + Type *CriuReqType `protobuf:"varint,1,req,name=type,enum=CriuReqType" json:"type,omitempty"` + Opts *CriuOpts `protobuf:"bytes,2,opt,name=opts" json:"opts,omitempty"` + NotifySuccess *bool `protobuf:"varint,3,opt,name=notify_success,json=notifySuccess" json:"notify_success,omitempty"` + // + // When set service won't close the connection but + // will wait for more req-s to appear. Works not + // for all request types. + KeepOpen *bool `protobuf:"varint,4,opt,name=keep_open,json=keepOpen" json:"keep_open,omitempty"` + // + // 'features' can be used to query which features + // are supported by the installed criu/kernel + // via RPC. + Features *CriuFeatures `protobuf:"bytes,5,opt,name=features" json:"features,omitempty"` + // 'pid' is used for WAIT_PID + Pid *uint32 `protobuf:"varint,6,opt,name=pid" json:"pid,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CriuReq) Reset() { *m = CriuReq{} } +func (m *CriuReq) String() string { return proto.CompactTextString(m) } +func (*CriuReq) ProtoMessage() {} +func (*CriuReq) Descriptor() ([]byte, []int) { + return fileDescriptor_d9874a201429861e, []int{12} +} + +func (m *CriuReq) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CriuReq.Unmarshal(m, b) +} +func (m *CriuReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CriuReq.Marshal(b, m, deterministic) +} +func (m *CriuReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_CriuReq.Merge(m, src) +} +func (m *CriuReq) XXX_Size() int { + return xxx_messageInfo_CriuReq.Size(m) +} +func (m *CriuReq) XXX_DiscardUnknown() { + xxx_messageInfo_CriuReq.DiscardUnknown(m) +} + +var xxx_messageInfo_CriuReq proto.InternalMessageInfo + +func (m *CriuReq) GetType() CriuReqType { + if m != nil && m.Type != nil { + return *m.Type + } + return CriuReqType_EMPTY +} + +func (m *CriuReq) GetOpts() *CriuOpts { + if m != nil { + return m.Opts + } + return nil +} + +func (m *CriuReq) GetNotifySuccess() bool { + if m != nil && m.NotifySuccess != nil { + return *m.NotifySuccess + } + return false +} + +func (m *CriuReq) GetKeepOpen() bool { + if m != nil && m.KeepOpen != nil { + return *m.KeepOpen + } + return false +} + +func (m *CriuReq) GetFeatures() *CriuFeatures { + if m != nil { + return m.Features + } + return nil +} + +func (m *CriuReq) GetPid() uint32 { + if m != nil && m.Pid != nil { + return *m.Pid + } + return 0 +} + +type CriuResp struct { + Type *CriuReqType `protobuf:"varint,1,req,name=type,enum=CriuReqType" json:"type,omitempty"` + Success *bool `protobuf:"varint,2,req,name=success" json:"success,omitempty"` + Dump *CriuDumpResp `protobuf:"bytes,3,opt,name=dump" json:"dump,omitempty"` + Restore *CriuRestoreResp `protobuf:"bytes,4,opt,name=restore" json:"restore,omitempty"` + Notify *CriuNotify `protobuf:"bytes,5,opt,name=notify" json:"notify,omitempty"` + Ps *CriuPageServerInfo `protobuf:"bytes,6,opt,name=ps" json:"ps,omitempty"` + CrErrno *int32 `protobuf:"varint,7,opt,name=cr_errno,json=crErrno" json:"cr_errno,omitempty"` + Features *CriuFeatures `protobuf:"bytes,8,opt,name=features" json:"features,omitempty"` + CrErrmsg *string `protobuf:"bytes,9,opt,name=cr_errmsg,json=crErrmsg" json:"cr_errmsg,omitempty"` + Version *CriuVersion `protobuf:"bytes,10,opt,name=version" json:"version,omitempty"` + Status *int32 `protobuf:"varint,11,opt,name=status" json:"status,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CriuResp) Reset() { *m = CriuResp{} } +func (m *CriuResp) String() string { return proto.CompactTextString(m) } +func (*CriuResp) ProtoMessage() {} +func (*CriuResp) Descriptor() ([]byte, []int) { + return fileDescriptor_d9874a201429861e, []int{13} +} + +func (m *CriuResp) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CriuResp.Unmarshal(m, b) +} +func (m *CriuResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CriuResp.Marshal(b, m, deterministic) +} +func (m *CriuResp) XXX_Merge(src proto.Message) { + xxx_messageInfo_CriuResp.Merge(m, src) +} +func (m *CriuResp) XXX_Size() int { + return xxx_messageInfo_CriuResp.Size(m) +} +func (m *CriuResp) XXX_DiscardUnknown() { + xxx_messageInfo_CriuResp.DiscardUnknown(m) +} + +var xxx_messageInfo_CriuResp proto.InternalMessageInfo + +func (m *CriuResp) GetType() CriuReqType { + if m != nil && m.Type != nil { + return *m.Type + } + return CriuReqType_EMPTY +} + +func (m *CriuResp) GetSuccess() bool { + if m != nil && m.Success != nil { + return *m.Success + } + return false +} + +func (m *CriuResp) GetDump() *CriuDumpResp { + if m != nil { + return m.Dump + } + return nil +} + +func (m *CriuResp) GetRestore() *CriuRestoreResp { + if m != nil { + return m.Restore + } + return nil +} + +func (m *CriuResp) GetNotify() *CriuNotify { + if m != nil { + return m.Notify + } + return nil +} + +func (m *CriuResp) GetPs() *CriuPageServerInfo { + if m != nil { + return m.Ps + } + return nil +} + +func (m *CriuResp) GetCrErrno() int32 { + if m != nil && m.CrErrno != nil { + return *m.CrErrno + } + return 0 +} + +func (m *CriuResp) GetFeatures() *CriuFeatures { + if m != nil { + return m.Features + } + return nil +} + +func (m *CriuResp) GetCrErrmsg() string { + if m != nil && m.CrErrmsg != nil { + return *m.CrErrmsg + } + return "" +} + +func (m *CriuResp) GetVersion() *CriuVersion { + if m != nil { + return m.Version + } + return nil +} + +func (m *CriuResp) GetStatus() int32 { + if m != nil && m.Status != nil { + return *m.Status + } + return 0 +} + +// Answer for criu_req_type.VERSION requests +type CriuVersion struct { + MajorNumber *int32 `protobuf:"varint,1,req,name=major_number,json=majorNumber" json:"major_number,omitempty"` + MinorNumber *int32 `protobuf:"varint,2,req,name=minor_number,json=minorNumber" json:"minor_number,omitempty"` + Gitid *string `protobuf:"bytes,3,opt,name=gitid" json:"gitid,omitempty"` + Sublevel *int32 `protobuf:"varint,4,opt,name=sublevel" json:"sublevel,omitempty"` + Extra *int32 `protobuf:"varint,5,opt,name=extra" json:"extra,omitempty"` + Name *string `protobuf:"bytes,6,opt,name=name" json:"name,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CriuVersion) Reset() { *m = CriuVersion{} } +func (m *CriuVersion) String() string { return proto.CompactTextString(m) } +func (*CriuVersion) ProtoMessage() {} +func (*CriuVersion) Descriptor() ([]byte, []int) { + return fileDescriptor_d9874a201429861e, []int{14} +} + +func (m *CriuVersion) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CriuVersion.Unmarshal(m, b) +} +func (m *CriuVersion) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CriuVersion.Marshal(b, m, deterministic) +} +func (m *CriuVersion) XXX_Merge(src proto.Message) { + xxx_messageInfo_CriuVersion.Merge(m, src) +} +func (m *CriuVersion) XXX_Size() int { + return xxx_messageInfo_CriuVersion.Size(m) +} +func (m *CriuVersion) XXX_DiscardUnknown() { + xxx_messageInfo_CriuVersion.DiscardUnknown(m) +} + +var xxx_messageInfo_CriuVersion proto.InternalMessageInfo + +func (m *CriuVersion) GetMajorNumber() int32 { + if m != nil && m.MajorNumber != nil { + return *m.MajorNumber + } + return 0 +} + +func (m *CriuVersion) GetMinorNumber() int32 { + if m != nil && m.MinorNumber != nil { + return *m.MinorNumber + } + return 0 +} + +func (m *CriuVersion) GetGitid() string { + if m != nil && m.Gitid != nil { + return *m.Gitid + } + return "" +} + +func (m *CriuVersion) GetSublevel() int32 { + if m != nil && m.Sublevel != nil { + return *m.Sublevel + } + return 0 +} + +func (m *CriuVersion) GetExtra() int32 { + if m != nil && m.Extra != nil { + return *m.Extra + } + return 0 +} + +func (m *CriuVersion) GetName() string { + if m != nil && m.Name != nil { + return *m.Name + } + return "" +} + +func init() { + proto.RegisterEnum("CriuCgMode", CriuCgMode_name, CriuCgMode_value) + proto.RegisterEnum("CriuPreDumpMode", CriuPreDumpMode_name, CriuPreDumpMode_value) + proto.RegisterEnum("CriuReqType", CriuReqType_name, CriuReqType_value) + proto.RegisterType((*CriuPageServerInfo)(nil), "criu_page_server_info") + proto.RegisterType((*CriuVethPair)(nil), "criu_veth_pair") + proto.RegisterType((*ExtMountMap)(nil), "ext_mount_map") + proto.RegisterType((*JoinNamespace)(nil), "join_namespace") + proto.RegisterType((*InheritFd)(nil), "inherit_fd") + proto.RegisterType((*CgroupRoot)(nil), "cgroup_root") + proto.RegisterType((*UnixSk)(nil), "unix_sk") + proto.RegisterType((*CriuOpts)(nil), "criu_opts") + proto.RegisterType((*CriuDumpResp)(nil), "criu_dump_resp") + proto.RegisterType((*CriuRestoreResp)(nil), "criu_restore_resp") + proto.RegisterType((*CriuNotify)(nil), "criu_notify") + proto.RegisterType((*CriuFeatures)(nil), "criu_features") + proto.RegisterType((*CriuReq)(nil), "criu_req") + proto.RegisterType((*CriuResp)(nil), "criu_resp") + proto.RegisterType((*CriuVersion)(nil), "criu_version") +} + +func init() { proto.RegisterFile("rpc/rpc.proto", fileDescriptor_d9874a201429861e) } + +var fileDescriptor_d9874a201429861e = []byte{ + // 2033 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x57, 0xe9, 0x72, 0x1b, 0x37, + 0x12, 0x0e, 0x29, 0xf1, 0x02, 0x45, 0x79, 0x0c, 0x5f, 0x70, 0xbc, 0xb6, 0x15, 0x3a, 0x8e, 0xb5, + 0x8a, 0xc3, 0x24, 0x8a, 0x8f, 0xd8, 0x9b, 0xd4, 0x96, 0x8b, 0x22, 0x1d, 0xae, 0x75, 0xb0, 0x40, + 0xc9, 0x5b, 0xfe, 0x85, 0x1a, 0xcd, 0x80, 0x14, 0xac, 0x19, 0xcc, 0x2c, 0x00, 0x2a, 0x92, 0x5f, + 0x62, 0x5f, 0x65, 0x7f, 0xef, 0x53, 0xe4, 0x91, 0xb6, 0xba, 0x01, 0xca, 0x52, 0x9c, 0xaa, 0xec, + 0xbf, 0xe9, 0xaf, 0xbb, 0x81, 0xbe, 0xd1, 0x43, 0x3a, 0xa6, 0x4c, 0xbe, 0x35, 0x65, 0xd2, 0x2b, + 0x4d, 0xe1, 0x8a, 0xee, 0x8c, 0xdc, 0x48, 0x8c, 0x9a, 0x8b, 0x32, 0x9e, 0x49, 0x61, 0xa5, 0x39, + 0x91, 0x46, 0x28, 0x3d, 0x2d, 0x28, 0x23, 0x8d, 0x38, 0x4d, 0x8d, 0xb4, 0x96, 0x55, 0xd6, 0x2a, + 0xeb, 0x2d, 0xbe, 0x20, 0x29, 0x25, 0xcb, 0x65, 0x61, 0x1c, 0xab, 0xae, 0x55, 0xd6, 0x6b, 0x1c, + 0xbf, 0x69, 0x44, 0x96, 0x4a, 0x95, 0xb2, 0x25, 0x84, 0xe0, 0x93, 0xae, 0x92, 0xea, 0x34, 0x65, + 0xcb, 0x08, 0x54, 0xa7, 0x69, 0xf7, 0x27, 0xb2, 0x8a, 0x17, 0x9d, 0x48, 0x77, 0x24, 0xca, 0x58, + 0x19, 0x7a, 0x8d, 0xd4, 0xd4, 0x54, 0x28, 0xcd, 0x2a, 0x6b, 0xd5, 0xf5, 0x16, 0x5f, 0x56, 0xd3, + 0x91, 0xa6, 0x37, 0x48, 0x5d, 0x4d, 0x45, 0x31, 0x87, 0xe3, 0x01, 0xad, 0xa9, 0xe9, 0xde, 0xdc, + 0x75, 0x7f, 0x20, 0x1d, 0x79, 0xea, 0x44, 0x5e, 0xcc, 0xb5, 0x13, 0x79, 0x5c, 0xc2, 0x85, 0xc7, + 0xf2, 0x2c, 0xa8, 0xc2, 0x27, 0x20, 0x27, 0x71, 0x16, 0xd4, 0xe0, 0xb3, 0xfb, 0x96, 0xac, 0xbe, + 0x2f, 0x94, 0x16, 0x3a, 0xce, 0xa5, 0x2d, 0xe3, 0x44, 0x82, 0x51, 0xda, 0x06, 0xa5, 0xaa, 0xb6, + 0xf4, 0x16, 0x69, 0x68, 0x2b, 0xa6, 0x2a, 0x93, 0x41, 0xaf, 0xae, 0xed, 0x50, 0x65, 0x92, 0xde, + 0x21, 0x2d, 0x79, 0xea, 0x4c, 0x2c, 0x8a, 0xd2, 0xa1, 0x57, 0x2d, 0xde, 0x44, 0x60, 0xaf, 0x74, + 0xdd, 0x1e, 0x21, 0x4a, 0x1f, 0x49, 0xa3, 0x9c, 0x98, 0xa6, 0x7f, 0x60, 0x89, 0x77, 0x1d, 0x0e, + 0xf4, 0xae, 0x3f, 0x25, 0xed, 0x64, 0x66, 0x8a, 0x79, 0x29, 0x4c, 0x51, 0x38, 0x88, 0x5f, 0xe2, + 0x4c, 0x16, 0xc2, 0x8a, 0xdf, 0x18, 0xd3, 0xd8, 0x1d, 0x05, 0x2b, 0xf0, 0xbb, 0x7b, 0x9f, 0x34, + 0xe6, 0x5a, 0x9d, 0x0a, 0x7b, 0x4c, 0xaf, 0x93, 0x9a, 0xd2, 0x45, 0x2a, 0xf1, 0x96, 0x0e, 0xf7, + 0x44, 0xf7, 0xbf, 0x11, 0x69, 0x61, 0x4c, 0x8b, 0xd2, 0x59, 0xda, 0x25, 0x1d, 0x95, 0xc7, 0x33, + 0x69, 0x45, 0xaa, 0x8c, 0x98, 0xa6, 0x28, 0x5b, 0xe3, 0x6d, 0x0f, 0x6e, 0x29, 0x33, 0x4c, 0x17, + 0x69, 0xaa, 0x7e, 0x4c, 0xd3, 0x03, 0xd2, 0xc9, 0x64, 0x7c, 0x22, 0x85, 0x99, 0x6b, 0xad, 0xf4, + 0x0c, 0x9d, 0x6d, 0xf2, 0x15, 0x04, 0xb9, 0xc7, 0xe8, 0x3d, 0xd2, 0x86, 0xe8, 0x07, 0x6b, 0x30, + 0xa9, 0x4d, 0x0e, 0x01, 0x3a, 0xd0, 0xea, 0x74, 0x72, 0x4c, 0x1f, 0x91, 0x2b, 0x2e, 0x29, 0x85, + 0xb4, 0x2e, 0x3e, 0xcc, 0x94, 0x3d, 0x92, 0x29, 0xab, 0xa1, 0xcc, 0xaa, 0x4b, 0xca, 0xc1, 0x47, + 0x14, 0x04, 0xe5, 0x49, 0x6c, 0xd5, 0x89, 0x14, 0xa9, 0x3c, 0x51, 0x89, 0xb4, 0xac, 0xee, 0x05, + 0x03, 0xbc, 0xe5, 0x51, 0x88, 0xbf, 0x3d, 0x92, 0x59, 0x26, 0xde, 0x17, 0x87, 0xac, 0x81, 0x22, + 0x4d, 0x04, 0xfe, 0x51, 0x1c, 0xd2, 0xbb, 0x84, 0x40, 0xca, 0x44, 0x56, 0x24, 0xc7, 0x96, 0x35, + 0xbd, 0x35, 0x80, 0x6c, 0x03, 0x40, 0xef, 0x91, 0x56, 0x56, 0xcc, 0x44, 0x26, 0x4f, 0x64, 0xc6, + 0x5a, 0xe0, 0xea, 0xcb, 0xca, 0x26, 0x6f, 0x66, 0xc5, 0x6c, 0x1b, 0x20, 0x7a, 0x9b, 0xc0, 0xb7, + 0xcf, 0x3a, 0xf1, 0xa5, 0x9d, 0x15, 0x33, 0x4c, 0xfb, 0x57, 0xa4, 0x5a, 0x5a, 0xd6, 0x5e, 0xab, + 0xac, 0xb7, 0x37, 0x6f, 0xf6, 0xfe, 0xb0, 0x31, 0x78, 0xb5, 0xb4, 0xf4, 0x21, 0x59, 0xd5, 0x85, + 0x53, 0xd3, 0x33, 0x61, 0x13, 0xa3, 0x4a, 0x67, 0xd9, 0x0a, 0x5a, 0xd1, 0xf1, 0xe8, 0xc4, 0x83, + 0x90, 0x55, 0xc8, 0x38, 0xeb, 0xf8, 0x4c, 0x63, 0xf6, 0xef, 0x12, 0x52, 0xc6, 0x46, 0x6a, 0x27, + 0x54, 0x3e, 0x63, 0xab, 0xc8, 0x69, 0x79, 0x64, 0x94, 0xcf, 0xc0, 0x71, 0x67, 0xe2, 0xe4, 0x58, + 0xe4, 0x32, 0x67, 0x57, 0xbc, 0xe3, 0x08, 0xec, 0xc8, 0x1c, 0x74, 0xe3, 0xb9, 0x2b, 0x44, 0x2a, + 0xd3, 0x79, 0xc9, 0x22, 0xef, 0x38, 0x20, 0x5b, 0x00, 0x40, 0x9a, 0x7e, 0x2d, 0xcc, 0xf1, 0x22, + 0xff, 0x57, 0x31, 0xcb, 0x2d, 0x80, 0x7c, 0xf6, 0xef, 0x12, 0x92, 0x29, 0x7d, 0x2c, 0x8c, 0xcc, + 0xe3, 0x92, 0x51, 0xaf, 0x0e, 0x08, 0x07, 0x80, 0x3e, 0x24, 0x35, 0x68, 0x4e, 0xcb, 0xae, 0xad, + 0x2d, 0xad, 0xb7, 0x37, 0xaf, 0xf4, 0x2e, 0xf7, 0x2b, 0xf7, 0x5c, 0xfa, 0x80, 0x34, 0x92, 0x72, + 0x2e, 0x92, 0xb8, 0x64, 0xd7, 0xd7, 0x2a, 0xeb, 0x9d, 0x97, 0xe4, 0xc9, 0xe6, 0x8b, 0x27, 0x2f, + 0x9e, 0x3d, 0xdf, 0x7c, 0xf1, 0x94, 0xd7, 0x93, 0x72, 0xde, 0x8f, 0x4b, 0x7a, 0x9f, 0xb4, 0xa7, + 0x85, 0x49, 0xa4, 0x50, 0x06, 0xee, 0xba, 0x81, 0x77, 0x11, 0x84, 0x46, 0x80, 0x40, 0x12, 0xe4, + 0xa9, 0x4c, 0x44, 0x92, 0xa7, 0xec, 0xe6, 0xda, 0x12, 0x24, 0x01, 0xe8, 0x7e, 0x0e, 0x45, 0xd2, + 0xc0, 0x5e, 0xd7, 0x8e, 0xdd, 0x42, 0x4b, 0x56, 0x7b, 0x97, 0x7a, 0x9f, 0xd7, 0xe5, 0xa9, 0xdb, + 0xd1, 0x0e, 0xb2, 0x90, 0xc7, 0x1a, 0xf2, 0xe3, 0xdb, 0xcb, 0x32, 0xe6, 0xb3, 0xe0, 0xd1, 0xbe, + 0x07, 0xe9, 0x43, 0xd2, 0x48, 0x66, 0xd8, 0x7a, 0xec, 0x36, 0x9e, 0xb7, 0xd2, 0xbb, 0xd0, 0x8e, + 0xbc, 0x9e, 0xcc, 0x38, 0x24, 0xe6, 0x3e, 0x69, 0x1b, 0xeb, 0x84, 0x55, 0x87, 0x19, 0xf4, 0xc1, + 0xe7, 0xde, 0x64, 0x63, 0xdd, 0xc4, 0x23, 0x74, 0xe3, 0x62, 0xdb, 0xb3, 0x3b, 0x78, 0x54, 0xbb, + 0xf7, 0x11, 0xe2, 0xad, 0xf0, 0x3d, 0x4c, 0xe9, 0x1a, 0x59, 0xc1, 0x4c, 0x2d, 0x1c, 0xf9, 0x8b, + 0x3f, 0x0d, 0xb0, 0x81, 0x37, 0xfe, 0xbe, 0xef, 0x29, 0x7b, 0x14, 0x1b, 0xb8, 0xee, 0xae, 0x17, + 0x90, 0xa7, 0x6e, 0xe2, 0x91, 0x85, 0x40, 0x1e, 0x5b, 0x27, 0x8d, 0x65, 0xf7, 0xce, 0x05, 0x76, + 0x3c, 0x02, 0x21, 0xb4, 0xc7, 0xaa, 0xc4, 0xf3, 0xef, 0xfb, 0x10, 0x02, 0x0d, 0x87, 0xc3, 0xf8, + 0xd2, 0xf1, 0x61, 0x26, 0xc5, 0xd4, 0xb2, 0x35, 0xe4, 0x35, 0x3d, 0x30, 0xb4, 0x74, 0x9d, 0xb4, + 0x43, 0x27, 0x0b, 0xa5, 0x0b, 0xf6, 0x05, 0x3a, 0xd2, 0xec, 0x05, 0x8c, 0xb7, 0xe6, 0xd8, 0xd4, + 0x23, 0x5d, 0xd0, 0x9f, 0xc9, 0xb5, 0xcb, 0x01, 0x16, 0x39, 0x0c, 0xa1, 0xee, 0x5a, 0x65, 0x7d, + 0x75, 0xb3, 0xe3, 0xeb, 0x23, 0x99, 0x21, 0xc8, 0xaf, 0x5e, 0x0a, 0xfa, 0x4e, 0x91, 0x4a, 0xb8, + 0x68, 0x76, 0x54, 0x58, 0x27, 0x32, 0x95, 0x2b, 0xc7, 0x1e, 0x60, 0xb5, 0x34, 0xbe, 0xff, 0xee, + 0xc9, 0x8f, 0x4f, 0x9f, 0x3f, 0xe3, 0x04, 0x79, 0xdb, 0xc0, 0xa2, 0xeb, 0x24, 0xc2, 0x42, 0x11, + 0x36, 0x89, 0xb5, 0x80, 0xe9, 0x67, 0xd9, 0x97, 0x68, 0xf6, 0x2a, 0xe2, 0x93, 0x24, 0xd6, 0x63, + 0x40, 0xe9, 0xe7, 0x50, 0x37, 0x4e, 0x1a, 0x1d, 0x67, 0xec, 0x61, 0x70, 0x2c, 0xd0, 0x58, 0x53, + 0x79, 0xe9, 0xce, 0x84, 0xb6, 0xec, 0x2b, 0xb8, 0x8c, 0x37, 0x90, 0xde, 0x05, 0x9f, 0x1b, 0xfe, + 0x29, 0xb0, 0xec, 0x51, 0xa8, 0xee, 0xcb, 0x4f, 0x03, 0xaf, 0x03, 0xbd, 0x6b, 0xe9, 0x17, 0x64, + 0x25, 0x54, 0x47, 0x69, 0x8a, 0xd2, 0xb2, 0xbf, 0x62, 0x87, 0x86, 0x01, 0x3e, 0x06, 0x88, 0x6e, + 0x90, 0xab, 0x17, 0x45, 0xfc, 0x24, 0xd9, 0x40, 0xb9, 0x2b, 0x17, 0xe4, 0x70, 0xa2, 0x3c, 0x21, + 0x37, 0x83, 0x6c, 0x3a, 0xcf, 0x4b, 0x91, 0x14, 0xda, 0x99, 0x22, 0xcb, 0xa4, 0x61, 0x5f, 0xa3, + 0xf5, 0xd7, 0x3d, 0x77, 0x6b, 0x9e, 0x97, 0xfd, 0x73, 0x1e, 0x4c, 0xe5, 0xa9, 0x91, 0xf2, 0xc3, + 0x22, 0xf0, 0xec, 0x31, 0x9e, 0xbe, 0xe2, 0x41, 0x1f, 0x63, 0x78, 0xa1, 0x9d, 0xca, 0x25, 0xbc, + 0x95, 0xdf, 0x78, 0x6f, 0x03, 0x49, 0xbf, 0x26, 0x14, 0xe6, 0x31, 0x56, 0x87, 0xd2, 0x62, 0x9a, + 0xa9, 0xd9, 0x91, 0x63, 0x3d, 0xac, 0x20, 0x98, 0xd4, 0x93, 0x63, 0x55, 0x8e, 0xf4, 0x10, 0x61, + 0x70, 0xf8, 0x57, 0x19, 0x1f, 0x0b, 0x7b, 0x66, 0x13, 0x97, 0x59, 0xf6, 0x2d, 0x8a, 0xb5, 0x01, + 0x9b, 0x78, 0x08, 0x07, 0x47, 0xfc, 0xe1, 0x0c, 0x67, 0xa1, 0x65, 0xdf, 0x85, 0xc1, 0x11, 0x7f, + 0x38, 0x1b, 0x03, 0x80, 0xc3, 0xda, 0xc5, 0x6e, 0x6e, 0xa1, 0x2f, 0xbe, 0xc7, 0xa9, 0xd3, 0xf4, + 0xc0, 0x30, 0x85, 0x60, 0x15, 0xa6, 0x3c, 0x82, 0xb4, 0x3a, 0x1b, 0xaa, 0x99, 0x6d, 0x7a, 0x53, + 0x3c, 0x63, 0xec, 0xac, 0x2f, 0x69, 0x28, 0xf9, 0xa4, 0xd0, 0x53, 0x15, 0x86, 0xf3, 0x0f, 0xe8, + 0x34, 0xf1, 0xd0, 0xe2, 0x59, 0x06, 0xc7, 0x92, 0xac, 0xb0, 0x92, 0x3d, 0x09, 0xd3, 0x31, 0x29, + 0xfb, 0x40, 0x83, 0x76, 0x66, 0x73, 0xc8, 0x09, 0x6a, 0x3f, 0xf5, 0xda, 0x99, 0xcd, 0xc7, 0x1e, + 0x01, 0x37, 0x5c, 0x66, 0x45, 0x12, 0x27, 0xd2, 0x38, 0xf6, 0xcc, 0x8f, 0x5e, 0x97, 0xd9, 0x3e, + 0x02, 0x78, 0xb8, 0x67, 0x9b, 0x8c, 0x3d, 0xf7, 0x6f, 0xbe, 0xe7, 0x1a, 0xac, 0x2d, 0x64, 0x82, + 0xe6, 0x8f, 0xfe, 0xd1, 0x00, 0x1e, 0xe8, 0xdd, 0x22, 0xf0, 0x29, 0x60, 0x09, 0x78, 0x81, 0x9c, + 0xba, 0xcb, 0xec, 0x1b, 0xbf, 0x91, 0x40, 0x40, 0x5f, 0xa2, 0x9d, 0xf0, 0x49, 0x1f, 0x91, 0x08, + 0x44, 0x75, 0x21, 0x12, 0x2d, 0x4e, 0xa4, 0x51, 0xd3, 0x33, 0xf6, 0x37, 0x3f, 0xb3, 0x5c, 0x66, + 0x77, 0x8b, 0xbe, 0x7e, 0x8b, 0x20, 0x46, 0xc2, 0x97, 0xcd, 0x59, 0x6c, 0x52, 0xf6, 0x53, 0x88, + 0x04, 0x42, 0xef, 0x62, 0x93, 0xd2, 0xbf, 0x93, 0x4e, 0x69, 0xa4, 0x2f, 0x2a, 0x6c, 0xca, 0x9f, + 0xb1, 0x29, 0xaf, 0x85, 0x47, 0xeb, 0x22, 0xeb, 0x65, 0x7d, 0x32, 0xde, 0x1e, 0xf5, 0x07, 0xbc, + 0x5d, 0x1a, 0x09, 0x85, 0x06, 0xcd, 0xd9, 0x7d, 0x1c, 0xf6, 0x31, 0x14, 0x33, 0xd2, 0x96, 0xd0, + 0x5a, 0x46, 0x5a, 0x57, 0x18, 0x99, 0xe2, 0x6e, 0xd2, 0xe4, 0xe7, 0x74, 0xf7, 0x21, 0xb9, 0x8a, + 0xd2, 0x01, 0xf0, 0x0a, 0x61, 0x9b, 0xf0, 0x7b, 0x06, 0x7c, 0x76, 0x9f, 0x93, 0x36, 0x8a, 0xf9, + 0x67, 0x90, 0xde, 0x24, 0x75, 0xff, 0x3e, 0x86, 0x5d, 0x27, 0x50, 0x9f, 0xae, 0x21, 0xdd, 0x37, + 0xa4, 0x83, 0x8a, 0x53, 0x19, 0xbb, 0xb9, 0xf1, 0x35, 0x95, 0xcb, 0x5c, 0xe0, 0xd3, 0xb7, 0xb0, + 0x26, 0x97, 0xf9, 0x3e, 0xd0, 0xbf, 0xab, 0xc7, 0xea, 0xef, 0xea, 0xb1, 0xfb, 0x5b, 0x85, 0x34, + 0x83, 0xb5, 0xff, 0xa2, 0x5d, 0xb2, 0xec, 0xce, 0x4a, 0xbf, 0x39, 0xad, 0x6e, 0xae, 0xf6, 0x16, + 0x0c, 0x01, 0x28, 0x47, 0x1e, 0xbd, 0x47, 0x96, 0x61, 0x85, 0xc2, 0x93, 0xda, 0x9b, 0xa4, 0x77, + 0xbe, 0x54, 0x71, 0xc4, 0x2f, 0x3e, 0xf7, 0xf3, 0x24, 0x81, 0x95, 0x78, 0xe9, 0xd2, 0x73, 0xef, + 0x41, 0xb0, 0xf9, 0x58, 0xca, 0x52, 0x14, 0xa5, 0xd4, 0x61, 0x49, 0x6a, 0x02, 0xb0, 0x57, 0x4a, + 0x4d, 0x37, 0x48, 0x73, 0xe1, 0x1c, 0x2e, 0x47, 0xed, 0x85, 0x2d, 0x0b, 0x94, 0x9f, 0xf3, 0x17, + 0xf1, 0xa9, 0x63, 0x57, 0x63, 0x7c, 0xfe, 0xbd, 0x14, 0x56, 0x3d, 0x0c, 0xfc, 0xff, 0xe3, 0x13, + 0x23, 0x8d, 0x85, 0xb1, 0xb0, 0x54, 0x36, 0xf9, 0x82, 0xa4, 0x0f, 0xc8, 0x32, 0x24, 0x1d, 0x7d, + 0x38, 0x7f, 0xe6, 0xcf, 0xcb, 0x80, 0x23, 0x93, 0x3e, 0x26, 0x8d, 0x90, 0x6b, 0xf4, 0xa4, 0xbd, + 0x49, 0x7b, 0x9f, 0x14, 0x00, 0x5f, 0x88, 0xd0, 0x2f, 0x49, 0xdd, 0x87, 0x22, 0xb8, 0xb6, 0xd2, + 0xbb, 0x50, 0x06, 0x3c, 0xf0, 0xc2, 0x76, 0x55, 0xff, 0xd3, 0xed, 0xea, 0x36, 0xa4, 0x4f, 0x48, + 0x63, 0x74, 0x81, 0xbb, 0x5f, 0x8d, 0x37, 0x12, 0x33, 0x00, 0xf2, 0x52, 0x14, 0x9b, 0x7f, 0x12, + 0xc5, 0x3b, 0x10, 0x32, 0x38, 0x26, 0xb7, 0x33, 0xdc, 0x03, 0x5b, 0xbc, 0x89, 0xe7, 0xe4, 0x76, + 0x06, 0x4b, 0xc6, 0x89, 0x34, 0x56, 0x15, 0x1a, 0x77, 0xc0, 0xf6, 0xe2, 0x39, 0x0b, 0x20, 0x5f, + 0x70, 0xb1, 0x86, 0x71, 0x96, 0xe1, 0x5a, 0x58, 0xe3, 0x81, 0xea, 0xfe, 0xa7, 0x42, 0x56, 0x2e, + 0x6a, 0xc0, 0x1c, 0xcd, 0xe3, 0xf7, 0x85, 0x11, 0x7a, 0x9e, 0x1f, 0x4a, 0xb3, 0x58, 0xbf, 0x11, + 0xdb, 0x45, 0x08, 0x45, 0x94, 0xfe, 0x28, 0x52, 0x0d, 0x22, 0x80, 0x05, 0x91, 0xeb, 0xa4, 0x36, + 0x53, 0x2e, 0xfc, 0x4a, 0xb5, 0xb8, 0x27, 0xa0, 0x35, 0xed, 0xfc, 0xd0, 0x6f, 0xb4, 0xcb, 0x61, + 0xc0, 0x06, 0x1a, 0x34, 0xf0, 0xcf, 0x04, 0x43, 0x5f, 0xe3, 0x9e, 0x80, 0xd5, 0x13, 0xde, 0x36, + 0x8c, 0x76, 0x8b, 0xe3, 0xf7, 0x86, 0x08, 0x16, 0x87, 0x27, 0x9b, 0x12, 0x52, 0x1f, 0xbd, 0xde, + 0xdd, 0xe3, 0x83, 0xe8, 0x33, 0xda, 0x26, 0x8d, 0xfe, 0x6b, 0xb1, 0xbb, 0xb7, 0x3b, 0x88, 0x2a, + 0xb4, 0x45, 0x6a, 0x63, 0xbe, 0x37, 0x9e, 0x44, 0x55, 0xda, 0x24, 0xcb, 0x93, 0xbd, 0xe1, 0x7e, + 0xb4, 0x04, 0x5f, 0xc3, 0x83, 0xed, 0xed, 0x68, 0x19, 0xf4, 0x26, 0xfb, 0x7c, 0xd4, 0xdf, 0x8f, + 0x6a, 0xa0, 0xb7, 0x35, 0x18, 0xbe, 0x3a, 0xd8, 0xde, 0x8f, 0xea, 0x1b, 0xdf, 0x10, 0xfa, 0xe9, + 0xf8, 0x41, 0x71, 0x1c, 0x40, 0x51, 0x05, 0xc4, 0xdf, 0xee, 0x08, 0x3e, 0x78, 0xb5, 0x15, 0x55, + 0x37, 0x7e, 0xab, 0x84, 0xae, 0x5f, 0x94, 0x2e, 0x5c, 0x3c, 0xd8, 0x19, 0xef, 0xbf, 0x8b, 0x3e, + 0x83, 0xeb, 0xb6, 0x0e, 0x76, 0xc6, 0x5e, 0x87, 0x0f, 0x26, 0xfb, 0x60, 0x67, 0x15, 0x24, 0xfa, + 0xbf, 0x0c, 0xfa, 0x6f, 0xa2, 0x25, 0xba, 0x42, 0x9a, 0x63, 0x3e, 0x10, 0x28, 0xb5, 0x4c, 0xaf, + 0x90, 0xf6, 0xf8, 0xd5, 0xeb, 0x81, 0x98, 0x0c, 0xf8, 0xdb, 0x01, 0x8f, 0x6a, 0x70, 0xed, 0xee, + 0xde, 0xfe, 0x68, 0xf8, 0x2e, 0xaa, 0xd3, 0x88, 0xac, 0xf4, 0xc7, 0x07, 0xa3, 0xdd, 0xe1, 0x9e, + 0x17, 0x6f, 0xd0, 0xab, 0xa4, 0xb3, 0x40, 0xfc, 0x79, 0x4d, 0x80, 0x86, 0x83, 0x57, 0xfb, 0x07, + 0x7c, 0x10, 0xa0, 0x16, 0x9a, 0x3b, 0xe0, 0x93, 0xd1, 0xde, 0x6e, 0x44, 0xe0, 0xbe, 0x7f, 0xbe, + 0x1a, 0xed, 0x8b, 0xf1, 0x68, 0x2b, 0x6a, 0xd3, 0xeb, 0x24, 0xba, 0x70, 0x9f, 0xe8, 0xff, 0xb2, + 0xbd, 0x15, 0xad, 0xfc, 0x2f, 0x00, 0x00, 0xff, 0xff, 0xc4, 0x45, 0x96, 0x6d, 0x5e, 0x0f, 0x00, + 0x00, +} diff --git a/src/runtime/vendor/github.com/containerd/containerd/pkg/runtimeoptions/v1/api.pb.go b/src/runtime/vendor/github.com/containerd/containerd/pkg/runtimeoptions/v1/api.pb.go new file mode 100644 index 000000000000..a224dc6f2136 --- /dev/null +++ b/src/runtime/vendor/github.com/containerd/containerd/pkg/runtimeoptions/v1/api.pb.go @@ -0,0 +1,397 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: github.com/containerd/containerd/pkg/runtimeoptions/v1/api.proto + +package runtimeoptions_v1 + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" + reflect "reflect" + strings "strings" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type Options struct { + // TypeUrl specifies the type of the content inside the config file. + TypeUrl string `protobuf:"bytes,1,opt,name=type_url,json=typeUrl,proto3" json:"type_url,omitempty"` + // ConfigPath specifies the filesystem location of the config file + // used by the runtime. + ConfigPath string `protobuf:"bytes,2,opt,name=config_path,json=configPath,proto3" json:"config_path,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Options) Reset() { *m = Options{} } +func (*Options) ProtoMessage() {} +func (*Options) Descriptor() ([]byte, []int) { + return fileDescriptor_7700dd27e3487aa6, []int{0} +} +func (m *Options) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Options) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Options.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Options) XXX_Merge(src proto.Message) { + xxx_messageInfo_Options.Merge(m, src) +} +func (m *Options) XXX_Size() int { + return m.Size() +} +func (m *Options) XXX_DiscardUnknown() { + xxx_messageInfo_Options.DiscardUnknown(m) +} + +var xxx_messageInfo_Options proto.InternalMessageInfo + +func (m *Options) GetTypeUrl() string { + if m != nil { + return m.TypeUrl + } + return "" +} + +func (m *Options) GetConfigPath() string { + if m != nil { + return m.ConfigPath + } + return "" +} + +func init() { + proto.RegisterType((*Options)(nil), "runtimeoptions.v1.Options") +} + +func init() { + proto.RegisterFile("github.com/containerd/containerd/pkg/runtimeoptions/v1/api.proto", fileDescriptor_7700dd27e3487aa6) +} + +var fileDescriptor_7700dd27e3487aa6 = []byte{ + // 214 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x72, 0x48, 0xcf, 0x2c, 0xc9, + 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0xcf, 0x2b, 0x49, 0xcc, 0xcc, 0x4b, 0x2d, + 0x4a, 0x41, 0x66, 0x16, 0x64, 0xa7, 0xeb, 0x17, 0x95, 0xe6, 0x95, 0x64, 0xe6, 0xa6, 0xe6, 0x17, + 0x94, 0x64, 0xe6, 0xe7, 0x15, 0xeb, 0x97, 0x19, 0xea, 0x27, 0x16, 0x64, 0xea, 0x15, 0x14, 0xe5, + 0x97, 0xe4, 0x0b, 0x09, 0xa2, 0x4a, 0xea, 0x95, 0x19, 0x4a, 0xe9, 0x22, 0x19, 0x9a, 0x9e, 0x9f, + 0x9e, 0xaf, 0x0f, 0x56, 0x99, 0x54, 0x9a, 0x06, 0xe6, 0x81, 0x39, 0x60, 0x16, 0xc4, 0x04, 0x25, + 0x57, 0x2e, 0x76, 0x7f, 0x88, 0x66, 0x21, 0x49, 0x2e, 0x8e, 0x92, 0xca, 0x82, 0xd4, 0xf8, 0xd2, + 0xa2, 0x1c, 0x09, 0x46, 0x05, 0x46, 0x0d, 0xce, 0x20, 0x76, 0x10, 0x3f, 0xb4, 0x28, 0x47, 0x48, + 0x9e, 0x8b, 0x3b, 0x39, 0x3f, 0x2f, 0x2d, 0x33, 0x3d, 0xbe, 0x20, 0xb1, 0x24, 0x43, 0x82, 0x09, + 0x2c, 0xcb, 0x05, 0x11, 0x0a, 0x48, 0x2c, 0xc9, 0x70, 0x4a, 0x3b, 0xf1, 0x50, 0x8e, 0xf1, 0xc6, + 0x43, 0x39, 0x86, 0x86, 0x47, 0x72, 0x8c, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, + 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x51, 0x1e, 0xe4, 0x79, 0xd4, 0x1a, 0x55, 0x24, + 0xbe, 0xcc, 0x30, 0x89, 0x0d, 0xec, 0x6a, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x91, 0x3c, + 0x3e, 0x79, 0x3b, 0x01, 0x00, 0x00, +} + +func (m *Options) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Options) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Options) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ConfigPath) > 0 { + i -= len(m.ConfigPath) + copy(dAtA[i:], m.ConfigPath) + i = encodeVarintApi(dAtA, i, uint64(len(m.ConfigPath))) + i-- + dAtA[i] = 0x12 + } + if len(m.TypeUrl) > 0 { + i -= len(m.TypeUrl) + copy(dAtA[i:], m.TypeUrl) + i = encodeVarintApi(dAtA, i, uint64(len(m.TypeUrl))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintApi(dAtA []byte, offset int, v uint64) int { + offset -= sovApi(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Options) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.TypeUrl) + if l > 0 { + n += 1 + l + sovApi(uint64(l)) + } + l = len(m.ConfigPath) + if l > 0 { + n += 1 + l + sovApi(uint64(l)) + } + return n +} + +func sovApi(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozApi(x uint64) (n int) { + return sovApi(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (this *Options) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&Options{`, + `TypeUrl:` + fmt.Sprintf("%v", this.TypeUrl) + `,`, + `ConfigPath:` + fmt.Sprintf("%v", this.ConfigPath) + `,`, + `}`, + }, "") + return s +} +func valueToStringApi(v interface{}) string { + rv := reflect.ValueOf(v) + if rv.IsNil() { + return "nil" + } + pv := reflect.Indirect(rv).Interface() + return fmt.Sprintf("*%v", pv) +} +func (m *Options) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApi + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Options: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Options: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TypeUrl", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApi + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthApi + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApi + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TypeUrl = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConfigPath", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApi + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthApi + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApi + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConfigPath = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipApi(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthApi + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipApi(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowApi + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowApi + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowApi + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthApi + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupApi + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthApi + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthApi = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowApi = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupApi = fmt.Errorf("proto: unexpected end of group") +) diff --git a/src/runtime/vendor/github.com/containerd/containerd/pkg/runtimeoptions/v1/api.proto b/src/runtime/vendor/github.com/containerd/containerd/pkg/runtimeoptions/v1/api.proto new file mode 100644 index 000000000000..c771ea10ee7c --- /dev/null +++ b/src/runtime/vendor/github.com/containerd/containerd/pkg/runtimeoptions/v1/api.proto @@ -0,0 +1,25 @@ +// To regenerate api.pb.go run `make protos` +syntax = "proto3"; + +package runtimeoptions.v1; + +import "github.com/gogo/protobuf/gogoproto/gogo.proto"; + +option (gogoproto.goproto_stringer_all) = false; +option (gogoproto.stringer_all) = true; +option (gogoproto.goproto_getters_all) = true; +option (gogoproto.marshaler_all) = true; +option (gogoproto.sizer_all) = true; +option (gogoproto.unmarshaler_all) = true; +option (gogoproto.goproto_unrecognized_all) = false; + + +option go_package = "github.com/containerd/containerd/pkg/runtimeoptions/v1;runtimeoptions_v1"; + +message Options { + // TypeUrl specifies the type of the content inside the config file. + string type_url = 1; + // ConfigPath specifies the filesystem location of the config file + // used by the runtime. + string config_path = 2; +} diff --git a/src/runtime/vendor/github.com/mrunalp/fileutils/.gitignore b/src/runtime/vendor/github.com/mrunalp/fileutils/.gitignore new file mode 100644 index 000000000000..aac977bcaea2 --- /dev/null +++ b/src/runtime/vendor/github.com/mrunalp/fileutils/.gitignore @@ -0,0 +1 @@ +/gocp diff --git a/src/runtime/vendor/github.com/mrunalp/fileutils/LICENSE b/src/runtime/vendor/github.com/mrunalp/fileutils/LICENSE new file mode 100644 index 000000000000..27448585ad49 --- /dev/null +++ b/src/runtime/vendor/github.com/mrunalp/fileutils/LICENSE @@ -0,0 +1,191 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2014 Docker, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/src/runtime/vendor/github.com/mrunalp/fileutils/MAINTAINERS b/src/runtime/vendor/github.com/mrunalp/fileutils/MAINTAINERS new file mode 100644 index 000000000000..4a2cafa5c481 --- /dev/null +++ b/src/runtime/vendor/github.com/mrunalp/fileutils/MAINTAINERS @@ -0,0 +1 @@ +Mrunal Patel (@mrunalp) diff --git a/src/runtime/vendor/github.com/mrunalp/fileutils/README.md b/src/runtime/vendor/github.com/mrunalp/fileutils/README.md new file mode 100644 index 000000000000..6cb4140eae02 --- /dev/null +++ b/src/runtime/vendor/github.com/mrunalp/fileutils/README.md @@ -0,0 +1,5 @@ +# fileutils + +Collection of utilities for file manipulation in golang + +The library is based on docker pkg/archive pkg/idtools but does copies instead of handling archive formats. diff --git a/src/runtime/vendor/github.com/mrunalp/fileutils/fileutils.go b/src/runtime/vendor/github.com/mrunalp/fileutils/fileutils.go new file mode 100644 index 000000000000..7421e6207f6b --- /dev/null +++ b/src/runtime/vendor/github.com/mrunalp/fileutils/fileutils.go @@ -0,0 +1,168 @@ +package fileutils + +import ( + "fmt" + "io" + "os" + "path/filepath" + "syscall" +) + +// CopyFile copies the file at source to dest +func CopyFile(source string, dest string) error { + si, err := os.Lstat(source) + if err != nil { + return err + } + + st, ok := si.Sys().(*syscall.Stat_t) + if !ok { + return fmt.Errorf("could not convert to syscall.Stat_t") + } + + uid := int(st.Uid) + gid := int(st.Gid) + modeType := si.Mode() & os.ModeType + + // Handle symlinks + if modeType == os.ModeSymlink { + target, err := os.Readlink(source) + if err != nil { + return err + } + if err := os.Symlink(target, dest); err != nil { + return err + } + } + + // Handle device files + if modeType == os.ModeDevice { + devMajor := int64(major(uint64(st.Rdev))) + devMinor := int64(minor(uint64(st.Rdev))) + mode := uint32(si.Mode() & os.ModePerm) + if si.Mode()&os.ModeCharDevice != 0 { + mode |= syscall.S_IFCHR + } else { + mode |= syscall.S_IFBLK + } + if err := syscall.Mknod(dest, mode, int(mkdev(devMajor, devMinor))); err != nil { + return err + } + } + + // Handle regular files + if si.Mode().IsRegular() { + err = copyInternal(source, dest) + if err != nil { + return err + } + } + + // Chown the file + if err := os.Lchown(dest, uid, gid); err != nil { + return err + } + + // Chmod the file + if !(modeType == os.ModeSymlink) { + if err := os.Chmod(dest, si.Mode()); err != nil { + return err + } + } + + return nil +} + +func copyInternal(source, dest string) (retErr error) { + sf, err := os.Open(source) + if err != nil { + return err + } + defer sf.Close() + + df, err := os.Create(dest) + if err != nil { + return err + } + defer func() { + err := df.Close() + if retErr == nil { + retErr = err + } + }() + + _, err = io.Copy(df, sf) + return err +} + +// CopyDirectory copies the files under the source directory +// to dest directory. The dest directory is created if it +// does not exist. +func CopyDirectory(source string, dest string) error { + fi, err := os.Stat(source) + if err != nil { + return err + } + + // Get owner. + st, ok := fi.Sys().(*syscall.Stat_t) + if !ok { + return fmt.Errorf("could not convert to syscall.Stat_t") + } + + // We have to pick an owner here anyway. + if err := MkdirAllNewAs(dest, fi.Mode(), int(st.Uid), int(st.Gid)); err != nil { + return err + } + + return filepath.Walk(source, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + // Get the relative path + relPath, err := filepath.Rel(source, path) + if err != nil { + return nil + } + + if info.IsDir() { + // Skip the source directory. + if path != source { + // Get the owner. + st, ok := info.Sys().(*syscall.Stat_t) + if !ok { + return fmt.Errorf("could not convert to syscall.Stat_t") + } + + uid := int(st.Uid) + gid := int(st.Gid) + + if err := os.Mkdir(filepath.Join(dest, relPath), info.Mode()); err != nil { + return err + } + + if err := os.Lchown(filepath.Join(dest, relPath), uid, gid); err != nil { + return err + } + } + return nil + } + + return CopyFile(path, filepath.Join(dest, relPath)) + }) +} + +// Gives a number indicating the device driver to be used to access the passed device +func major(device uint64) uint64 { + return (device >> 8) & 0xfff +} + +// Gives a number that serves as a flag to the device driver for the passed device +func minor(device uint64) uint64 { + return (device & 0xff) | ((device >> 12) & 0xfff00) +} + +func mkdev(major int64, minor int64) uint32 { + return uint32(((minor & 0xfff00) << 12) | ((major & 0xfff) << 8) | (minor & 0xff)) +} diff --git a/src/runtime/vendor/github.com/mrunalp/fileutils/go.mod b/src/runtime/vendor/github.com/mrunalp/fileutils/go.mod new file mode 100644 index 000000000000..d8971cabc469 --- /dev/null +++ b/src/runtime/vendor/github.com/mrunalp/fileutils/go.mod @@ -0,0 +1,3 @@ +module github.com/mrunalp/fileutils + +go 1.13 diff --git a/src/runtime/vendor/github.com/mrunalp/fileutils/idtools.go b/src/runtime/vendor/github.com/mrunalp/fileutils/idtools.go new file mode 100644 index 000000000000..bad6539df533 --- /dev/null +++ b/src/runtime/vendor/github.com/mrunalp/fileutils/idtools.go @@ -0,0 +1,54 @@ +package fileutils + +import ( + "os" + "path/filepath" + "syscall" +) + +// MkdirAllNewAs creates a directory (include any along the path) and then modifies +// ownership ONLY of newly created directories to the requested uid/gid. If the +// directories along the path exist, no change of ownership will be performed +func MkdirAllNewAs(path string, mode os.FileMode, ownerUID, ownerGID int) error { + // make an array containing the original path asked for, plus (for mkAll == true) + // all path components leading up to the complete path that don't exist before we MkdirAll + // so that we can chown all of them properly at the end. If chownExisting is false, we won't + // chown the full directory path if it exists + var paths []string + st, err := os.Stat(path) + if err != nil && os.IsNotExist(err) { + paths = []string{path} + } else if err == nil { + if !st.IsDir() { + return &os.PathError{Op: "mkdir", Path: path, Err: syscall.ENOTDIR} + } + // nothing to do; directory path fully exists already + return nil + } + + // walk back to "/" looking for directories which do not exist + // and add them to the paths array for chown after creation + dirPath := path + for { + dirPath = filepath.Dir(dirPath) + if dirPath == "/" { + break + } + if _, err := os.Stat(dirPath); err != nil && os.IsNotExist(err) { + paths = append(paths, dirPath) + } + } + + if err := os.MkdirAll(path, mode); err != nil { + return err + } + + // even if it existed, we will chown the requested path + any subpaths that + // didn't exist when we called MkdirAll + for _, pathComponent := range paths { + if err := os.Chown(pathComponent, ownerUID, ownerGID); err != nil { + return err + } + } + return nil +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/README.md b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/README.md new file mode 100644 index 000000000000..8b25d5c1c014 --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/README.md @@ -0,0 +1,330 @@ +# libcontainer + +[![GoDoc](https://godoc.org/github.com/opencontainers/runc/libcontainer?status.svg)](https://godoc.org/github.com/opencontainers/runc/libcontainer) + +Libcontainer provides a native Go implementation for creating containers +with namespaces, cgroups, capabilities, and filesystem access controls. +It allows you to manage the lifecycle of the container performing additional operations +after the container is created. + + +#### Container +A container is a self contained execution environment that shares the kernel of the +host system and which is (optionally) isolated from other containers in the system. + +#### Using libcontainer + +Because containers are spawned in a two step process you will need a binary that +will be executed as the init process for the container. In libcontainer, we use +the current binary (/proc/self/exe) to be executed as the init process, and use +arg "init", we call the first step process "bootstrap", so you always need a "init" +function as the entry of "bootstrap". + +In addition to the go init function the early stage bootstrap is handled by importing +[nsenter](https://github.com/opencontainers/runc/blob/master/libcontainer/nsenter/README.md). + +```go +import ( + _ "github.com/opencontainers/runc/libcontainer/nsenter" +) + +func init() { + if len(os.Args) > 1 && os.Args[1] == "init" { + runtime.GOMAXPROCS(1) + runtime.LockOSThread() + factory, _ := libcontainer.New("") + if err := factory.StartInitialization(); err != nil { + logrus.Fatal(err) + } + panic("--this line should have never been executed, congratulations--") + } +} +``` + +Then to create a container you first have to initialize an instance of a factory +that will handle the creation and initialization for a container. + +```go +factory, err := libcontainer.New("/var/lib/container", libcontainer.Cgroupfs, libcontainer.InitArgs(os.Args[0], "init")) +if err != nil { + logrus.Fatal(err) + return +} +``` + +Once you have an instance of the factory created we can create a configuration +struct describing how the container is to be created. A sample would look similar to this: + +```go +defaultMountFlags := unix.MS_NOEXEC | unix.MS_NOSUID | unix.MS_NODEV +config := &configs.Config{ + Rootfs: "/your/path/to/rootfs", + Capabilities: &configs.Capabilities{ + Bounding: []string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE", + }, + Effective: []string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE", + }, + Inheritable: []string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE", + }, + Permitted: []string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE", + }, + Ambient: []string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE", + }, + }, + Namespaces: configs.Namespaces([]configs.Namespace{ + {Type: configs.NEWNS}, + {Type: configs.NEWUTS}, + {Type: configs.NEWIPC}, + {Type: configs.NEWPID}, + {Type: configs.NEWUSER}, + {Type: configs.NEWNET}, + {Type: configs.NEWCGROUP}, + }), + Cgroups: &configs.Cgroup{ + Name: "test-container", + Parent: "system", + Resources: &configs.Resources{ + MemorySwappiness: nil, + Devices: specconv.AllowedDevices, + }, + }, + MaskPaths: []string{ + "/proc/kcore", + "/sys/firmware", + }, + ReadonlyPaths: []string{ + "/proc/sys", "/proc/sysrq-trigger", "/proc/irq", "/proc/bus", + }, + Devices: specconv.AllowedDevices, + Hostname: "testing", + Mounts: []*configs.Mount{ + { + Source: "proc", + Destination: "/proc", + Device: "proc", + Flags: defaultMountFlags, + }, + { + Source: "tmpfs", + Destination: "/dev", + Device: "tmpfs", + Flags: unix.MS_NOSUID | unix.MS_STRICTATIME, + Data: "mode=755", + }, + { + Source: "devpts", + Destination: "/dev/pts", + Device: "devpts", + Flags: unix.MS_NOSUID | unix.MS_NOEXEC, + Data: "newinstance,ptmxmode=0666,mode=0620,gid=5", + }, + { + Device: "tmpfs", + Source: "shm", + Destination: "/dev/shm", + Data: "mode=1777,size=65536k", + Flags: defaultMountFlags, + }, + { + Source: "mqueue", + Destination: "/dev/mqueue", + Device: "mqueue", + Flags: defaultMountFlags, + }, + { + Source: "sysfs", + Destination: "/sys", + Device: "sysfs", + Flags: defaultMountFlags | unix.MS_RDONLY, + }, + }, + UidMappings: []configs.IDMap{ + { + ContainerID: 0, + HostID: 1000, + Size: 65536, + }, + }, + GidMappings: []configs.IDMap{ + { + ContainerID: 0, + HostID: 1000, + Size: 65536, + }, + }, + Networks: []*configs.Network{ + { + Type: "loopback", + Address: "127.0.0.1/0", + Gateway: "localhost", + }, + }, + Rlimits: []configs.Rlimit{ + { + Type: unix.RLIMIT_NOFILE, + Hard: uint64(1025), + Soft: uint64(1025), + }, + }, +} +``` + +Once you have the configuration populated you can create a container: + +```go +container, err := factory.Create("container-id", config) +if err != nil { + logrus.Fatal(err) + return +} +``` + +To spawn bash as the initial process inside the container and have the +processes pid returned in order to wait, signal, or kill the process: + +```go +process := &libcontainer.Process{ + Args: []string{"/bin/bash"}, + Env: []string{"PATH=/bin"}, + User: "daemon", + Stdin: os.Stdin, + Stdout: os.Stdout, + Stderr: os.Stderr, + Init: true, +} + +err := container.Run(process) +if err != nil { + container.Destroy() + logrus.Fatal(err) + return +} + +// wait for the process to finish. +_, err := process.Wait() +if err != nil { + logrus.Fatal(err) +} + +// destroy the container. +container.Destroy() +``` + +Additional ways to interact with a running container are: + +```go +// return all the pids for all processes running inside the container. +processes, err := container.Processes() + +// get detailed cpu, memory, io, and network statistics for the container and +// it's processes. +stats, err := container.Stats() + +// pause all processes inside the container. +container.Pause() + +// resume all paused processes. +container.Resume() + +// send signal to container's init process. +container.Signal(signal) + +// update container resource constraints. +container.Set(config) + +// get current status of the container. +status, err := container.Status() + +// get current container's state information. +state, err := container.State() +``` + + +#### Checkpoint & Restore + +libcontainer now integrates [CRIU](http://criu.org/) for checkpointing and restoring containers. +This let's you save the state of a process running inside a container to disk, and then restore +that state into a new process, on the same machine or on another machine. + +`criu` version 1.5.2 or higher is required to use checkpoint and restore. +If you don't already have `criu` installed, you can build it from source, following the +[online instructions](http://criu.org/Installation). `criu` is also installed in the docker image +generated when building libcontainer with docker. + + +## Copyright and license + +Code and documentation copyright 2014 Docker, inc. +The code and documentation are released under the [Apache 2.0 license](../LICENSE). +The documentation is also released under Creative Commons Attribution 4.0 International License. +You may obtain a copy of the license, titled CC-BY-4.0, at http://creativecommons.org/licenses/by/4.0/. diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/SPEC.md b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/SPEC.md new file mode 100644 index 000000000000..07ebdc12153d --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/SPEC.md @@ -0,0 +1,465 @@ +## Container Specification - v1 + +This is the standard configuration for version 1 containers. It includes +namespaces, standard filesystem setup, a default Linux capability set, and +information about resource reservations. It also has information about any +populated environment settings for the processes running inside a container. + +Along with the configuration of how a container is created the standard also +discusses actions that can be performed on a container to manage and inspect +information about the processes running inside. + +The v1 profile is meant to be able to accommodate the majority of applications +with a strong security configuration. + +### System Requirements and Compatibility + +Minimum requirements: +* Kernel version - 3.10 recommended 2.6.2x minimum(with backported patches) +* Mounted cgroups with each subsystem in its own hierarchy + + +### Namespaces + +| Flag | Enabled | +| --------------- | ------- | +| CLONE_NEWPID | 1 | +| CLONE_NEWUTS | 1 | +| CLONE_NEWIPC | 1 | +| CLONE_NEWNET | 1 | +| CLONE_NEWNS | 1 | +| CLONE_NEWUSER | 1 | +| CLONE_NEWCGROUP | 1 | + +Namespaces are created for the container via the `unshare` syscall. + + +### Filesystem + +A root filesystem must be provided to a container for execution. The container +will use this root filesystem (rootfs) to jail and spawn processes inside where +the binaries and system libraries are local to that directory. Any binaries +to be executed must be contained within this rootfs. + +Mounts that happen inside the container are automatically cleaned up when the +container exits as the mount namespace is destroyed and the kernel will +unmount all the mounts that were setup within that namespace. + +For a container to execute properly there are certain filesystems that +are required to be mounted within the rootfs that the runtime will setup. + +| Path | Type | Flags | Data | +| ----------- | ------ | -------------------------------------- | ---------------------------------------- | +| /proc | proc | MS_NOEXEC,MS_NOSUID,MS_NODEV | | +| /dev | tmpfs | MS_NOEXEC,MS_STRICTATIME | mode=755 | +| /dev/shm | tmpfs | MS_NOEXEC,MS_NOSUID,MS_NODEV | mode=1777,size=65536k | +| /dev/mqueue | mqueue | MS_NOEXEC,MS_NOSUID,MS_NODEV | | +| /dev/pts | devpts | MS_NOEXEC,MS_NOSUID | newinstance,ptmxmode=0666,mode=620,gid=5 | +| /sys | sysfs | MS_NOEXEC,MS_NOSUID,MS_NODEV,MS_RDONLY | | + + +After a container's filesystems are mounted within the newly created +mount namespace `/dev` will need to be populated with a set of device nodes. +It is expected that a rootfs does not need to have any device nodes specified +for `/dev` within the rootfs as the container will setup the correct devices +that are required for executing a container's process. + +| Path | Mode | Access | +| ------------ | ---- | ---------- | +| /dev/null | 0666 | rwm | +| /dev/zero | 0666 | rwm | +| /dev/full | 0666 | rwm | +| /dev/tty | 0666 | rwm | +| /dev/random | 0666 | rwm | +| /dev/urandom | 0666 | rwm | + + +**ptmx** +`/dev/ptmx` will need to be a symlink to the host's `/dev/ptmx` within +the container. + +The use of a pseudo TTY is optional within a container and it should support both. +If a pseudo is provided to the container `/dev/console` will need to be +setup by binding the console in `/dev/` after it has been populated and mounted +in tmpfs. + +| Source | Destination | UID GID | Mode | Type | +| --------------- | ------------ | ------- | ---- | ---- | +| *pty host path* | /dev/console | 0 0 | 0600 | bind | + + +After `/dev/null` has been setup we check for any external links between +the container's io, STDIN, STDOUT, STDERR. If the container's io is pointing +to `/dev/null` outside the container we close and `dup2` the `/dev/null` +that is local to the container's rootfs. + + +After the container has `/proc` mounted a few standard symlinks are setup +within `/dev/` for the io. + +| Source | Destination | +| --------------- | ----------- | +| /proc/self/fd | /dev/fd | +| /proc/self/fd/0 | /dev/stdin | +| /proc/self/fd/1 | /dev/stdout | +| /proc/self/fd/2 | /dev/stderr | + +A `pivot_root` is used to change the root for the process, effectively +jailing the process inside the rootfs. + +```c +put_old = mkdir(...); +pivot_root(rootfs, put_old); +chdir("/"); +unmount(put_old, MS_DETACH); +rmdir(put_old); +``` + +For container's running with a rootfs inside `ramfs` a `MS_MOVE` combined +with a `chroot` is required as `pivot_root` is not supported in `ramfs`. + +```c +mount(rootfs, "/", NULL, MS_MOVE, NULL); +chroot("."); +chdir("/"); +``` + +The `umask` is set back to `0022` after the filesystem setup has been completed. + +### Resources + +Cgroups are used to handle resource allocation for containers. This includes +system resources like cpu, memory, and device access. + +| Subsystem | Enabled | +| ---------- | ------- | +| devices | 1 | +| memory | 1 | +| cpu | 1 | +| cpuacct | 1 | +| cpuset | 1 | +| blkio | 1 | +| perf_event | 1 | +| freezer | 1 | +| hugetlb | 1 | +| pids | 1 | + + +All cgroup subsystem are joined so that statistics can be collected from +each of the subsystems. Freezer does not expose any stats but is joined +so that containers can be paused and resumed. + +The parent process of the container's init must place the init pid inside +the correct cgroups before the initialization begins. This is done so +that no processes or threads escape the cgroups. This sync is +done via a pipe ( specified in the runtime section below ) that the container's +init process will block waiting for the parent to finish setup. + +### IntelRdt + +Intel platforms with new Xeon CPU support Resource Director Technology (RDT). +Cache Allocation Technology (CAT) and Memory Bandwidth Allocation (MBA) are +two sub-features of RDT. + +Cache Allocation Technology (CAT) provides a way for the software to restrict +cache allocation to a defined 'subset' of L3 cache which may be overlapping +with other 'subsets'. The different subsets are identified by class of +service (CLOS) and each CLOS has a capacity bitmask (CBM). + +Memory Bandwidth Allocation (MBA) provides indirect and approximate throttle +over memory bandwidth for the software. A user controls the resource by +indicating the percentage of maximum memory bandwidth or memory bandwidth limit +in MBps unit if MBA Software Controller is enabled. + +It can be used to handle L3 cache and memory bandwidth resources allocation +for containers if hardware and kernel support Intel RDT CAT and MBA features. + +In Linux 4.10 kernel or newer, the interface is defined and exposed via +"resource control" filesystem, which is a "cgroup-like" interface. + +Comparing with cgroups, it has similar process management lifecycle and +interfaces in a container. But unlike cgroups' hierarchy, it has single level +filesystem layout. + +CAT and MBA features are introduced in Linux 4.10 and 4.12 kernel via +"resource control" filesystem. + +Intel RDT "resource control" filesystem hierarchy: +``` +mount -t resctrl resctrl /sys/fs/resctrl +tree /sys/fs/resctrl +/sys/fs/resctrl/ +|-- info +| |-- L3 +| | |-- cbm_mask +| | |-- min_cbm_bits +| | |-- num_closids +| |-- MB +| |-- bandwidth_gran +| |-- delay_linear +| |-- min_bandwidth +| |-- num_closids +|-- ... +|-- schemata +|-- tasks +|-- + |-- ... + |-- schemata + |-- tasks +``` + +For runc, we can make use of `tasks` and `schemata` configuration for L3 +cache and memory bandwidth resources constraints. + +The file `tasks` has a list of tasks that belongs to this group (e.g., +" group). Tasks can be added to a group by writing the task ID +to the "tasks" file (which will automatically remove them from the previous +group to which they belonged). New tasks created by fork(2) and clone(2) are +added to the same group as their parent. + +The file `schemata` has a list of all the resources available to this group. +Each resource (L3 cache, memory bandwidth) has its own line and format. + +L3 cache schema: +It has allocation bitmasks/values for L3 cache on each socket, which +contains L3 cache id and capacity bitmask (CBM). +``` + Format: "L3:=;=;..." +``` +For example, on a two-socket machine, the schema line could be "L3:0=ff;1=c0" +which means L3 cache id 0's CBM is 0xff, and L3 cache id 1's CBM is 0xc0. + +The valid L3 cache CBM is a *contiguous bits set* and number of bits that can +be set is less than the max bit. The max bits in the CBM is varied among +supported Intel CPU models. Kernel will check if it is valid when writing. +e.g., default value 0xfffff in root indicates the max bits of CBM is 20 +bits, which mapping to entire L3 cache capacity. Some valid CBM values to +set in a group: 0xf, 0xf0, 0x3ff, 0x1f00 and etc. + +Memory bandwidth schema: +It has allocation values for memory bandwidth on each socket, which contains +L3 cache id and memory bandwidth. +``` + Format: "MB:=bandwidth0;=bandwidth1;..." +``` +For example, on a two-socket machine, the schema line could be "MB:0=20;1=70" + +The minimum bandwidth percentage value for each CPU model is predefined and +can be looked up through "info/MB/min_bandwidth". The bandwidth granularity +that is allocated is also dependent on the CPU model and can be looked up at +"info/MB/bandwidth_gran". The available bandwidth control steps are: +min_bw + N * bw_gran. Intermediate values are rounded to the next control +step available on the hardware. + +If MBA Software Controller is enabled through mount option "-o mba_MBps" +mount -t resctrl resctrl -o mba_MBps /sys/fs/resctrl +We could specify memory bandwidth in "MBps" (Mega Bytes per second) unit +instead of "percentages". The kernel underneath would use a software feedback +mechanism or a "Software Controller" which reads the actual bandwidth using +MBM counters and adjust the memory bandwidth percentages to ensure: +"actual memory bandwidth < user specified memory bandwidth". + +For example, on a two-socket machine, the schema line could be +"MB:0=5000;1=7000" which means 5000 MBps memory bandwidth limit on socket 0 +and 7000 MBps memory bandwidth limit on socket 1. + +For more information about Intel RDT kernel interface: +https://www.kernel.org/doc/Documentation/x86/intel_rdt_ui.txt + +``` +An example for runc: +Consider a two-socket machine with two L3 caches where the default CBM is +0x7ff and the max CBM length is 11 bits, and minimum memory bandwidth of 10% +with a memory bandwidth granularity of 10%. + +Tasks inside the container only have access to the "upper" 7/11 of L3 cache +on socket 0 and the "lower" 5/11 L3 cache on socket 1, and may use a +maximum memory bandwidth of 20% on socket 0 and 70% on socket 1. + +"linux": { + "intelRdt": { + "closID": "guaranteed_group", + "l3CacheSchema": "L3:0=7f0;1=1f", + "memBwSchema": "MB:0=20;1=70" + } +} +``` + +### Security + +The standard set of Linux capabilities that are set in a container +provide a good default for security and flexibility for the applications. + + +| Capability | Enabled | +| -------------------- | ------- | +| CAP_NET_RAW | 1 | +| CAP_NET_BIND_SERVICE | 1 | +| CAP_AUDIT_READ | 1 | +| CAP_AUDIT_WRITE | 1 | +| CAP_DAC_OVERRIDE | 1 | +| CAP_SETFCAP | 1 | +| CAP_SETPCAP | 1 | +| CAP_SETGID | 1 | +| CAP_SETUID | 1 | +| CAP_MKNOD | 1 | +| CAP_CHOWN | 1 | +| CAP_FOWNER | 1 | +| CAP_FSETID | 1 | +| CAP_KILL | 1 | +| CAP_SYS_CHROOT | 1 | +| CAP_NET_BROADCAST | 0 | +| CAP_SYS_MODULE | 0 | +| CAP_SYS_RAWIO | 0 | +| CAP_SYS_PACCT | 0 | +| CAP_SYS_ADMIN | 0 | +| CAP_SYS_NICE | 0 | +| CAP_SYS_RESOURCE | 0 | +| CAP_SYS_TIME | 0 | +| CAP_SYS_TTY_CONFIG | 0 | +| CAP_AUDIT_CONTROL | 0 | +| CAP_MAC_OVERRIDE | 0 | +| CAP_MAC_ADMIN | 0 | +| CAP_NET_ADMIN | 0 | +| CAP_SYSLOG | 0 | +| CAP_DAC_READ_SEARCH | 0 | +| CAP_LINUX_IMMUTABLE | 0 | +| CAP_IPC_LOCK | 0 | +| CAP_IPC_OWNER | 0 | +| CAP_SYS_PTRACE | 0 | +| CAP_SYS_BOOT | 0 | +| CAP_LEASE | 0 | +| CAP_WAKE_ALARM | 0 | +| CAP_BLOCK_SUSPEND | 0 | + + +Additional security layers like [apparmor](https://wiki.ubuntu.com/AppArmor) +and [selinux](http://selinuxproject.org/page/Main_Page) can be used with +the containers. A container should support setting an apparmor profile or +selinux process and mount labels if provided in the configuration. + +Standard apparmor profile: +```c +#include +profile flags=(attach_disconnected,mediate_deleted) { + #include + network, + capability, + file, + umount, + + deny @{PROC}/sys/fs/** wklx, + deny @{PROC}/sysrq-trigger rwklx, + deny @{PROC}/mem rwklx, + deny @{PROC}/kmem rwklx, + deny @{PROC}/sys/kernel/[^s][^h][^m]* wklx, + deny @{PROC}/sys/kernel/*/** wklx, + + deny mount, + + deny /sys/[^f]*/** wklx, + deny /sys/f[^s]*/** wklx, + deny /sys/fs/[^c]*/** wklx, + deny /sys/fs/c[^g]*/** wklx, + deny /sys/fs/cg[^r]*/** wklx, + deny /sys/firmware/efi/efivars/** rwklx, + deny /sys/kernel/security/** rwklx, +} +``` + +*TODO: seccomp work is being done to find a good default config* + +### Runtime and Init Process + +During container creation the parent process needs to talk to the container's init +process and have a form of synchronization. This is accomplished by creating +a pipe that is passed to the container's init. When the init process first spawns +it will block on its side of the pipe until the parent closes its side. This +allows the parent to have time to set the new process inside a cgroup hierarchy +and/or write any uid/gid mappings required for user namespaces. +The pipe is passed to the init process via FD 3. + +The application consuming libcontainer should be compiled statically. libcontainer +does not define any init process and the arguments provided are used to `exec` the +process inside the application. There should be no long running init within the +container spec. + +If a pseudo tty is provided to a container it will open and `dup2` the console +as the container's STDIN, STDOUT, STDERR as well as mounting the console +as `/dev/console`. + +An extra set of mounts are provided to a container and setup for use. A container's +rootfs can contain some non portable files inside that can cause side effects during +execution of a process. These files are usually created and populated with the container +specific information via the runtime. + +**Extra runtime files:** +* /etc/hosts +* /etc/resolv.conf +* /etc/hostname +* /etc/localtime + + +#### Defaults + +There are a few defaults that can be overridden by users, but in their omission +these apply to processes within a container. + +| Type | Value | +| ------------------- | ------------------------------ | +| Parent Death Signal | SIGKILL | +| UID | 0 | +| GID | 0 | +| GROUPS | 0, NULL | +| CWD | "/" | +| $HOME | Current user's home dir or "/" | +| Readonly rootfs | false | +| Pseudo TTY | false | + + +## Actions + +After a container is created there is a standard set of actions that can +be done to the container. These actions are part of the public API for +a container. + +| Action | Description | +| -------------- | ------------------------------------------------------------------ | +| Get processes | Return all the pids for processes running inside a container | +| Get Stats | Return resource statistics for the container as a whole | +| Wait | Waits on the container's init process ( pid 1 ) | +| Wait Process | Wait on any of the container's processes returning the exit status | +| Destroy | Kill the container's init process and remove any filesystem state | +| Signal | Send a signal to the container's init process | +| Signal Process | Send a signal to any of the container's processes | +| Pause | Pause all processes inside the container | +| Resume | Resume all processes inside the container if paused | +| Exec | Execute a new process inside of the container ( requires setns ) | +| Set | Setup configs of the container after it's created | + +### Execute a new process inside of a running container + +User can execute a new process inside of a running container. Any binaries to be +executed must be accessible within the container's rootfs. + +The started process will run inside the container's rootfs. Any changes +made by the process to the container's filesystem will persist after the +process finished executing. + +The started process will join all the container's existing namespaces. When the +container is paused, the process will also be paused and will resume when +the container is unpaused. The started process will only run when the container's +primary process (PID 1) is running, and will not be restarted when the container +is restarted. + +#### Planned additions + +The started process will have its own cgroups nested inside the container's +cgroups. This is used for process tracking and optionally resource allocation +handling for the new process. Freezer cgroup is required, the rest of the cgroups +are optional. The process executor must place its pid inside the correct +cgroups before starting the process. This is done so that no child processes or +threads can escape the cgroups. + +When the process is stopped, the process executor will try (in a best-effort way) +to stop all its children and remove the sub-cgroups. diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_linux.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_linux.go new file mode 100644 index 000000000000..73965f12d83b --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_linux.go @@ -0,0 +1,54 @@ +package apparmor + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + + "github.com/opencontainers/runc/libcontainer/utils" +) + +// IsEnabled returns true if apparmor is enabled for the host. +func IsEnabled() bool { + if _, err := os.Stat("/sys/kernel/security/apparmor"); err == nil { + buf, err := ioutil.ReadFile("/sys/module/apparmor/parameters/enabled") + return err == nil && bytes.HasPrefix(buf, []byte("Y")) + } + return false +} + +func setProcAttr(attr, value string) error { + // Under AppArmor you can only change your own attr, so use /proc/self/ + // instead of /proc// like libapparmor does + f, err := os.OpenFile("/proc/self/attr/"+attr, os.O_WRONLY, 0) + if err != nil { + return err + } + defer f.Close() + + if err := utils.EnsureProcHandle(f); err != nil { + return err + } + + _, err = f.WriteString(value) + return err +} + +// changeOnExec reimplements aa_change_onexec from libapparmor in Go +func changeOnExec(name string) error { + if err := setProcAttr("exec", "exec "+name); err != nil { + return fmt.Errorf("apparmor failed to apply profile: %s", err) + } + return nil +} + +// ApplyProfile will apply the profile with the specified name to the process after +// the next exec. +func ApplyProfile(name string) error { + if name == "" { + return nil + } + + return changeOnExec(name) +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_unsupported.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_unsupported.go new file mode 100644 index 000000000000..0bc473f810bc --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_unsupported.go @@ -0,0 +1,20 @@ +// +build !linux + +package apparmor + +import ( + "errors" +) + +var ErrApparmorNotEnabled = errors.New("apparmor: config provided but apparmor not supported") + +func IsEnabled() bool { + return false +} + +func ApplyProfile(name string) error { + if name != "" { + return ErrApparmorNotEnabled + } + return nil +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/capabilities/capabilities.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/capabilities/capabilities.go new file mode 100644 index 000000000000..adbf6330c48e --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/capabilities/capabilities.go @@ -0,0 +1,96 @@ +// +build linux + +package capabilities + +import ( + "fmt" + "strings" + + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/syndtr/gocapability/capability" +) + +const allCapabilityTypes = capability.CAPS | capability.BOUNDS | capability.AMBS + +var capabilityMap map[string]capability.Cap + +func init() { + capabilityMap = make(map[string]capability.Cap, capability.CAP_LAST_CAP+1) + for _, c := range capability.List() { + if c > capability.CAP_LAST_CAP { + continue + } + capabilityMap["CAP_"+strings.ToUpper(c.String())] = c + } +} + +// New creates a new Caps from the given Capabilities config. +func New(capConfig *configs.Capabilities) (*Caps, error) { + var ( + err error + caps Caps + ) + + if caps.bounding, err = capSlice(capConfig.Bounding); err != nil { + return nil, err + } + if caps.effective, err = capSlice(capConfig.Effective); err != nil { + return nil, err + } + if caps.inheritable, err = capSlice(capConfig.Inheritable); err != nil { + return nil, err + } + if caps.permitted, err = capSlice(capConfig.Permitted); err != nil { + return nil, err + } + if caps.ambient, err = capSlice(capConfig.Ambient); err != nil { + return nil, err + } + if caps.pid, err = capability.NewPid2(0); err != nil { + return nil, err + } + if err = caps.pid.Load(); err != nil { + return nil, err + } + return &caps, nil +} + +func capSlice(caps []string) ([]capability.Cap, error) { + out := make([]capability.Cap, len(caps)) + for i, c := range caps { + v, ok := capabilityMap[c] + if !ok { + return nil, fmt.Errorf("unknown capability %q", c) + } + out[i] = v + } + return out, nil +} + +// Caps holds the capabilities for a container. +type Caps struct { + pid capability.Capabilities + bounding []capability.Cap + effective []capability.Cap + inheritable []capability.Cap + permitted []capability.Cap + ambient []capability.Cap +} + +// ApplyBoundingSet sets the capability bounding set to those specified in the whitelist. +func (c *Caps) ApplyBoundingSet() error { + c.pid.Clear(capability.BOUNDS) + c.pid.Set(capability.BOUNDS, c.bounding...) + return c.pid.Apply(capability.BOUNDS) +} + +// Apply sets all the capabilities for the current process in the config. +func (c *Caps) ApplyCaps() error { + c.pid.Clear(allCapabilityTypes) + c.pid.Set(capability.BOUNDS, c.bounding...) + c.pid.Set(capability.PERMITTED, c.permitted...) + c.pid.Set(capability.INHERITABLE, c.inheritable...) + c.pid.Set(capability.EFFECTIVE, c.effective...) + c.pid.Set(capability.AMBIENT, c.ambient...) + return c.pid.Apply(allCapabilityTypes) +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/capabilities/capabilities_unsupported.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/capabilities/capabilities_unsupported.go new file mode 100644 index 000000000000..a3e82ac1fd4d --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/capabilities/capabilities_unsupported.go @@ -0,0 +1,3 @@ +// +build !linux + +package capabilities diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go new file mode 100644 index 000000000000..717d0f00a340 --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go @@ -0,0 +1,90 @@ +package validate + +import ( + "errors" + "fmt" + "strings" + + "github.com/opencontainers/runc/libcontainer/configs" +) + +// rootlessEUID makes sure that the config can be applied when runc +// is being executed as a non-root user (euid != 0) in the current user namespace. +func (v *ConfigValidator) rootlessEUID(config *configs.Config) error { + if err := rootlessEUIDMappings(config); err != nil { + return err + } + if err := rootlessEUIDMount(config); err != nil { + return err + } + + // XXX: We currently can't verify the user config at all, because + // configs.Config doesn't store the user-related configs. So this + // has to be verified by setupUser() in init_linux.go. + + return nil +} + +func hasIDMapping(id int, mappings []configs.IDMap) bool { + for _, m := range mappings { + if id >= m.ContainerID && id < m.ContainerID+m.Size { + return true + } + } + return false +} + +func rootlessEUIDMappings(config *configs.Config) error { + if !config.Namespaces.Contains(configs.NEWUSER) { + return errors.New("rootless container requires user namespaces") + } + + if len(config.UidMappings) == 0 { + return errors.New("rootless containers requires at least one UID mapping") + } + if len(config.GidMappings) == 0 { + return errors.New("rootless containers requires at least one GID mapping") + } + return nil +} + +// mount verifies that the user isn't trying to set up any mounts they don't have +// the rights to do. In addition, it makes sure that no mount has a `uid=` or +// `gid=` option that doesn't resolve to root. +func rootlessEUIDMount(config *configs.Config) error { + // XXX: We could whitelist allowed devices at this point, but I'm not + // convinced that's a good idea. The kernel is the best arbiter of + // access control. + + for _, mount := range config.Mounts { + // Check that the options list doesn't contain any uid= or gid= entries + // that don't resolve to root. + for _, opt := range strings.Split(mount.Data, ",") { + if strings.HasPrefix(opt, "uid=") { + var uid int + n, err := fmt.Sscanf(opt, "uid=%d", &uid) + if n != 1 || err != nil { + // Ignore unknown mount options. + continue + } + if !hasIDMapping(uid, config.UidMappings) { + return errors.New("cannot specify uid= mount options for unmapped uid in rootless containers") + } + } + + if strings.HasPrefix(opt, "gid=") { + var gid int + n, err := fmt.Sscanf(opt, "gid=%d", &gid) + if n != 1 || err != nil { + // Ignore unknown mount options. + continue + } + if !hasIDMapping(gid, config.GidMappings) { + return errors.New("cannot specify gid= mount options for unmapped gid in rootless containers") + } + } + } + } + + return nil +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go new file mode 100644 index 000000000000..63abdb00cb07 --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go @@ -0,0 +1,239 @@ +package validate + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "strings" + "sync" + + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/intelrdt" + selinux "github.com/opencontainers/selinux/go-selinux" + "golang.org/x/sys/unix" +) + +type Validator interface { + Validate(*configs.Config) error +} + +func New() Validator { + return &ConfigValidator{} +} + +type ConfigValidator struct { +} + +func (v *ConfigValidator) Validate(config *configs.Config) error { + if err := v.rootfs(config); err != nil { + return err + } + if err := v.network(config); err != nil { + return err + } + if err := v.hostname(config); err != nil { + return err + } + if err := v.security(config); err != nil { + return err + } + if err := v.usernamespace(config); err != nil { + return err + } + if err := v.cgroupnamespace(config); err != nil { + return err + } + if err := v.sysctl(config); err != nil { + return err + } + if err := v.intelrdt(config); err != nil { + return err + } + if config.RootlessEUID { + if err := v.rootlessEUID(config); err != nil { + return err + } + } + return nil +} + +// rootfs validates if the rootfs is an absolute path and is not a symlink +// to the container's root filesystem. +func (v *ConfigValidator) rootfs(config *configs.Config) error { + if _, err := os.Stat(config.Rootfs); err != nil { + if os.IsNotExist(err) { + return fmt.Errorf("rootfs (%s) does not exist", config.Rootfs) + } + return err + } + cleaned, err := filepath.Abs(config.Rootfs) + if err != nil { + return err + } + if cleaned, err = filepath.EvalSymlinks(cleaned); err != nil { + return err + } + if filepath.Clean(config.Rootfs) != cleaned { + return fmt.Errorf("%s is not an absolute path or is a symlink", config.Rootfs) + } + return nil +} + +func (v *ConfigValidator) network(config *configs.Config) error { + if !config.Namespaces.Contains(configs.NEWNET) { + if len(config.Networks) > 0 || len(config.Routes) > 0 { + return errors.New("unable to apply network settings without a private NET namespace") + } + } + return nil +} + +func (v *ConfigValidator) hostname(config *configs.Config) error { + if config.Hostname != "" && !config.Namespaces.Contains(configs.NEWUTS) { + return errors.New("unable to set hostname without a private UTS namespace") + } + return nil +} + +func (v *ConfigValidator) security(config *configs.Config) error { + // restrict sys without mount namespace + if (len(config.MaskPaths) > 0 || len(config.ReadonlyPaths) > 0) && + !config.Namespaces.Contains(configs.NEWNS) { + return errors.New("unable to restrict sys entries without a private MNT namespace") + } + if config.ProcessLabel != "" && !selinux.GetEnabled() { + return errors.New("selinux label is specified in config, but selinux is disabled or not supported") + } + + return nil +} + +func (v *ConfigValidator) usernamespace(config *configs.Config) error { + if config.Namespaces.Contains(configs.NEWUSER) { + if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) { + return errors.New("USER namespaces aren't enabled in the kernel") + } + } else { + if config.UidMappings != nil || config.GidMappings != nil { + return errors.New("User namespace mappings specified, but USER namespace isn't enabled in the config") + } + } + return nil +} + +func (v *ConfigValidator) cgroupnamespace(config *configs.Config) error { + if config.Namespaces.Contains(configs.NEWCGROUP) { + if _, err := os.Stat("/proc/self/ns/cgroup"); os.IsNotExist(err) { + return errors.New("cgroup namespaces aren't enabled in the kernel") + } + } + return nil +} + +// sysctl validates that the specified sysctl keys are valid or not. +// /proc/sys isn't completely namespaced and depending on which namespaces +// are specified, a subset of sysctls are permitted. +func (v *ConfigValidator) sysctl(config *configs.Config) error { + validSysctlMap := map[string]bool{ + "kernel.msgmax": true, + "kernel.msgmnb": true, + "kernel.msgmni": true, + "kernel.sem": true, + "kernel.shmall": true, + "kernel.shmmax": true, + "kernel.shmmni": true, + "kernel.shm_rmid_forced": true, + } + + var ( + netOnce sync.Once + hostnet bool + hostnetErr error + ) + + for s := range config.Sysctl { + if validSysctlMap[s] || strings.HasPrefix(s, "fs.mqueue.") { + if config.Namespaces.Contains(configs.NEWIPC) { + continue + } else { + return fmt.Errorf("sysctl %q is not allowed in the hosts ipc namespace", s) + } + } + if strings.HasPrefix(s, "net.") { + // Is container using host netns? + // Here "host" means "current", not "initial". + netOnce.Do(func() { + if !config.Namespaces.Contains(configs.NEWNET) { + hostnet = true + return + } + path := config.Namespaces.PathOf(configs.NEWNET) + if path == "" { + // own netns, so hostnet = false + return + } + hostnet, hostnetErr = isHostNetNS(path) + }) + if hostnetErr != nil { + return hostnetErr + } + if hostnet { + return fmt.Errorf("sysctl %q not allowed in host network namespace", s) + } + continue + } + if config.Namespaces.Contains(configs.NEWUTS) { + switch s { + case "kernel.domainname": + // This is namespaced and there's no explicit OCI field for it. + continue + case "kernel.hostname": + // This is namespaced but there's a conflicting (dedicated) OCI field for it. + return fmt.Errorf("sysctl %q is not allowed as it conflicts with the OCI %q field", s, "hostname") + } + } + return fmt.Errorf("sysctl %q is not in a separate kernel namespace", s) + } + + return nil +} + +func (v *ConfigValidator) intelrdt(config *configs.Config) error { + if config.IntelRdt != nil { + if !intelrdt.IsCATEnabled() && !intelrdt.IsMBAEnabled() { + return errors.New("intelRdt is specified in config, but Intel RDT is not supported or enabled") + } + + if !intelrdt.IsCATEnabled() && config.IntelRdt.L3CacheSchema != "" { + return errors.New("intelRdt.l3CacheSchema is specified in config, but Intel RDT/CAT is not enabled") + } + if !intelrdt.IsMBAEnabled() && config.IntelRdt.MemBwSchema != "" { + return errors.New("intelRdt.memBwSchema is specified in config, but Intel RDT/MBA is not enabled") + } + + if intelrdt.IsCATEnabled() && config.IntelRdt.L3CacheSchema == "" { + return errors.New("Intel RDT/CAT is enabled and intelRdt is specified in config, but intelRdt.l3CacheSchema is empty") + } + if intelrdt.IsMBAEnabled() && config.IntelRdt.MemBwSchema == "" { + return errors.New("Intel RDT/MBA is enabled and intelRdt is specified in config, but intelRdt.memBwSchema is empty") + } + } + + return nil +} + +func isHostNetNS(path string) (bool, error) { + const currentProcessNetns = "/proc/self/ns/net" + + var st1, st2 unix.Stat_t + + if err := unix.Stat(currentProcessNetns, &st1); err != nil { + return false, fmt.Errorf("unable to stat %q: %s", currentProcessNetns, err) + } + if err := unix.Stat(path, &st2); err != nil { + return false, fmt.Errorf("unable to stat %q: %s", path, err) + } + + return (st1.Dev == st2.Dev) && (st1.Ino == st2.Ino), nil +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/console_linux.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/console_linux.go new file mode 100644 index 000000000000..9997e93ed4f3 --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/console_linux.go @@ -0,0 +1,41 @@ +package libcontainer + +import ( + "os" + + "golang.org/x/sys/unix" +) + +// mount initializes the console inside the rootfs mounting with the specified mount label +// and applying the correct ownership of the console. +func mountConsole(slavePath string) error { + oldMask := unix.Umask(0000) + defer unix.Umask(oldMask) + f, err := os.Create("/dev/console") + if err != nil && !os.IsExist(err) { + return err + } + if f != nil { + f.Close() + } + return unix.Mount(slavePath, "/dev/console", "bind", unix.MS_BIND, "") +} + +// dupStdio opens the slavePath for the console and dups the fds to the current +// processes stdio, fd 0,1,2. +func dupStdio(slavePath string) error { + fd, err := unix.Open(slavePath, unix.O_RDWR, 0) + if err != nil { + return &os.PathError{ + Op: "open", + Path: slavePath, + Err: err, + } + } + for _, i := range []int{0, 1, 2} { + if err := unix.Dup3(fd, i, 0); err != nil { + return err + } + } + return nil +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/container.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/container.go new file mode 100644 index 000000000000..ba7541c5fd68 --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/container.go @@ -0,0 +1,173 @@ +// Package libcontainer provides a native Go implementation for creating containers +// with namespaces, cgroups, capabilities, and filesystem access controls. +// It allows you to manage the lifecycle of the container performing additional operations +// after the container is created. +package libcontainer + +import ( + "os" + "time" + + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runtime-spec/specs-go" +) + +// Status is the status of a container. +type Status int + +const ( + // Created is the status that denotes the container exists but has not been run yet. + Created Status = iota + // Running is the status that denotes the container exists and is running. + Running + // Pausing is the status that denotes the container exists, it is in the process of being paused. + Pausing + // Paused is the status that denotes the container exists, but all its processes are paused. + Paused + // Stopped is the status that denotes the container does not have a created or running process. + Stopped +) + +func (s Status) String() string { + switch s { + case Created: + return "created" + case Running: + return "running" + case Pausing: + return "pausing" + case Paused: + return "paused" + case Stopped: + return "stopped" + default: + return "unknown" + } +} + +// BaseState represents the platform agnostic pieces relating to a +// running container's state +type BaseState struct { + // ID is the container ID. + ID string `json:"id"` + + // InitProcessPid is the init process id in the parent namespace. + InitProcessPid int `json:"init_process_pid"` + + // InitProcessStartTime is the init process start time in clock cycles since boot time. + InitProcessStartTime uint64 `json:"init_process_start"` + + // Created is the unix timestamp for the creation time of the container in UTC + Created time.Time `json:"created"` + + // Config is the container's configuration. + Config configs.Config `json:"config"` +} + +// BaseContainer is a libcontainer container object. +// +// Each container is thread-safe within the same process. Since a container can +// be destroyed by a separate process, any function may return that the container +// was not found. BaseContainer includes methods that are platform agnostic. +type BaseContainer interface { + // Returns the ID of the container + ID() string + + // Returns the current status of the container. + // + // errors: + // ContainerNotExists - Container no longer exists, + // Systemerror - System error. + Status() (Status, error) + + // State returns the current container's state information. + // + // errors: + // SystemError - System error. + State() (*State, error) + + // OCIState returns the current container's state information. + // + // errors: + // SystemError - System error. + OCIState() (*specs.State, error) + + // Returns the current config of the container. + Config() configs.Config + + // Returns the PIDs inside this container. The PIDs are in the namespace of the calling process. + // + // errors: + // ContainerNotExists - Container no longer exists, + // Systemerror - System error. + // + // Some of the returned PIDs may no longer refer to processes in the Container, unless + // the Container state is PAUSED in which case every PID in the slice is valid. + Processes() ([]int, error) + + // Returns statistics for the container. + // + // errors: + // ContainerNotExists - Container no longer exists, + // Systemerror - System error. + Stats() (*Stats, error) + + // Set resources of container as configured + // + // We can use this to change resources when containers are running. + // + // errors: + // SystemError - System error. + Set(config configs.Config) error + + // Start a process inside the container. Returns error if process fails to + // start. You can track process lifecycle with passed Process structure. + // + // errors: + // ContainerNotExists - Container no longer exists, + // ConfigInvalid - config is invalid, + // ContainerPaused - Container is paused, + // SystemError - System error. + Start(process *Process) (err error) + + // Run immediately starts the process inside the container. Returns error if process + // fails to start. It does not block waiting for the exec fifo after start returns but + // opens the fifo after start returns. + // + // errors: + // ContainerNotExists - Container no longer exists, + // ConfigInvalid - config is invalid, + // ContainerPaused - Container is paused, + // SystemError - System error. + Run(process *Process) (err error) + + // Destroys the container, if its in a valid state, after killing any + // remaining running processes. + // + // Any event registrations are removed before the container is destroyed. + // No error is returned if the container is already destroyed. + // + // Running containers must first be stopped using Signal(..). + // Paused containers must first be resumed using Resume(..). + // + // errors: + // ContainerNotStopped - Container is still running, + // ContainerPaused - Container is paused, + // SystemError - System error. + Destroy() error + + // Signal sends the provided signal code to the container's initial process. + // + // If all is specified the signal is sent to all processes in the container + // including the initial process. + // + // errors: + // SystemError - System error. + Signal(s os.Signal, all bool) error + + // Exec signals the container to exec the users process at the end of the init. + // + // errors: + // SystemError - System error. + Exec() error +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go new file mode 100644 index 000000000000..3dca29e4c3f2 --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go @@ -0,0 +1,2095 @@ +// +build linux + +package libcontainer + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io" + "io/ioutil" + "net" + "os" + "os/exec" + "path/filepath" + "reflect" + "strconv" + "strings" + "sync" + "time" + + securejoin "github.com/cyphar/filepath-securejoin" + "github.com/opencontainers/runc/libcontainer/cgroups" + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/intelrdt" + "github.com/opencontainers/runc/libcontainer/system" + "github.com/opencontainers/runc/libcontainer/utils" + "github.com/opencontainers/runtime-spec/specs-go" + + "github.com/checkpoint-restore/go-criu/v4" + criurpc "github.com/checkpoint-restore/go-criu/v4/rpc" + "github.com/golang/protobuf/proto" + errorsf "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "github.com/vishvananda/netlink/nl" + "golang.org/x/sys/unix" +) + +const stdioFdCount = 3 + +type linuxContainer struct { + id string + root string + config *configs.Config + cgroupManager cgroups.Manager + intelRdtManager intelrdt.Manager + initPath string + initArgs []string + initProcess parentProcess + initProcessStartTime uint64 + criuPath string + newuidmapPath string + newgidmapPath string + m sync.Mutex + criuVersion int + state containerState + created time.Time +} + +// State represents a running container's state +type State struct { + BaseState + + // Platform specific fields below here + + // Specified if the container was started under the rootless mode. + // Set to true if BaseState.Config.RootlessEUID && BaseState.Config.RootlessCgroups + Rootless bool `json:"rootless"` + + // Paths to all the container's cgroups, as returned by (*cgroups.Manager).GetPaths + // + // For cgroup v1, a key is cgroup subsystem name, and the value is the path + // to the cgroup for this subsystem. + // + // For cgroup v2 unified hierarchy, a key is "", and the value is the unified path. + CgroupPaths map[string]string `json:"cgroup_paths"` + + // NamespacePaths are filepaths to the container's namespaces. Key is the namespace type + // with the value as the path. + NamespacePaths map[configs.NamespaceType]string `json:"namespace_paths"` + + // Container's standard descriptors (std{in,out,err}), needed for checkpoint and restore + ExternalDescriptors []string `json:"external_descriptors,omitempty"` + + // Intel RDT "resource control" filesystem path + IntelRdtPath string `json:"intel_rdt_path"` +} + +// Container is a libcontainer container object. +// +// Each container is thread-safe within the same process. Since a container can +// be destroyed by a separate process, any function may return that the container +// was not found. +type Container interface { + BaseContainer + + // Methods below here are platform specific + + // Checkpoint checkpoints the running container's state to disk using the criu(8) utility. + // + // errors: + // Systemerror - System error. + Checkpoint(criuOpts *CriuOpts) error + + // Restore restores the checkpointed container to a running state using the criu(8) utility. + // + // errors: + // Systemerror - System error. + Restore(process *Process, criuOpts *CriuOpts) error + + // If the Container state is RUNNING or CREATED, sets the Container state to PAUSING and pauses + // the execution of any user processes. Asynchronously, when the container finished being paused the + // state is changed to PAUSED. + // If the Container state is PAUSED, do nothing. + // + // errors: + // ContainerNotExists - Container no longer exists, + // ContainerNotRunning - Container not running or created, + // Systemerror - System error. + Pause() error + + // If the Container state is PAUSED, resumes the execution of any user processes in the + // Container before setting the Container state to RUNNING. + // If the Container state is RUNNING, do nothing. + // + // errors: + // ContainerNotExists - Container no longer exists, + // ContainerNotPaused - Container is not paused, + // Systemerror - System error. + Resume() error + + // NotifyOOM returns a read-only channel signaling when the container receives an OOM notification. + // + // errors: + // Systemerror - System error. + NotifyOOM() (<-chan struct{}, error) + + // NotifyMemoryPressure returns a read-only channel signaling when the container reaches a given pressure level + // + // errors: + // Systemerror - System error. + NotifyMemoryPressure(level PressureLevel) (<-chan struct{}, error) +} + +// ID returns the container's unique ID +func (c *linuxContainer) ID() string { + return c.id +} + +// Config returns the container's configuration +func (c *linuxContainer) Config() configs.Config { + return *c.config +} + +func (c *linuxContainer) Status() (Status, error) { + c.m.Lock() + defer c.m.Unlock() + return c.currentStatus() +} + +func (c *linuxContainer) State() (*State, error) { + c.m.Lock() + defer c.m.Unlock() + return c.currentState() +} + +func (c *linuxContainer) OCIState() (*specs.State, error) { + c.m.Lock() + defer c.m.Unlock() + return c.currentOCIState() +} + +func (c *linuxContainer) Processes() ([]int, error) { + var pids []int + status, err := c.currentStatus() + if err != nil { + return pids, err + } + // for systemd cgroup, the unit's cgroup path will be auto removed if container's all processes exited + if status == Stopped && !c.cgroupManager.Exists() { + return pids, nil + } + + pids, err = c.cgroupManager.GetAllPids() + if err != nil { + return nil, newSystemErrorWithCause(err, "getting all container pids from cgroups") + } + return pids, nil +} + +func (c *linuxContainer) Stats() (*Stats, error) { + var ( + err error + stats = &Stats{} + ) + if stats.CgroupStats, err = c.cgroupManager.GetStats(); err != nil { + return stats, newSystemErrorWithCause(err, "getting container stats from cgroups") + } + if c.intelRdtManager != nil { + if stats.IntelRdtStats, err = c.intelRdtManager.GetStats(); err != nil { + return stats, newSystemErrorWithCause(err, "getting container's Intel RDT stats") + } + } + for _, iface := range c.config.Networks { + switch iface.Type { + case "veth": + istats, err := getNetworkInterfaceStats(iface.HostInterfaceName) + if err != nil { + return stats, newSystemErrorWithCausef(err, "getting network stats for interface %q", iface.HostInterfaceName) + } + stats.Interfaces = append(stats.Interfaces, istats) + } + } + return stats, nil +} + +func (c *linuxContainer) Set(config configs.Config) error { + c.m.Lock() + defer c.m.Unlock() + status, err := c.currentStatus() + if err != nil { + return err + } + if status == Stopped { + return newGenericError(errors.New("container not running"), ContainerNotRunning) + } + if err := c.cgroupManager.Set(&config); err != nil { + // Set configs back + if err2 := c.cgroupManager.Set(c.config); err2 != nil { + logrus.Warnf("Setting back cgroup configs failed due to error: %v, your state.json and actual configs might be inconsistent.", err2) + } + return err + } + if c.intelRdtManager != nil { + if err := c.intelRdtManager.Set(&config); err != nil { + // Set configs back + if err2 := c.cgroupManager.Set(c.config); err2 != nil { + logrus.Warnf("Setting back cgroup configs failed due to error: %v, your state.json and actual configs might be inconsistent.", err2) + } + if err2 := c.intelRdtManager.Set(c.config); err2 != nil { + logrus.Warnf("Setting back intelrdt configs failed due to error: %v, your state.json and actual configs might be inconsistent.", err2) + } + return err + } + } + // After config setting succeed, update config and states + c.config = &config + _, err = c.updateState(nil) + return err +} + +func (c *linuxContainer) Start(process *Process) error { + c.m.Lock() + defer c.m.Unlock() + if c.config.Cgroups.Resources.SkipDevices { + return newGenericError(errors.New("can't start container with SkipDevices set"), ConfigInvalid) + } + if process.Init { + if err := c.createExecFifo(); err != nil { + return err + } + } + if err := c.start(process); err != nil { + if process.Init { + c.deleteExecFifo() + } + return err + } + return nil +} + +func (c *linuxContainer) Run(process *Process) error { + if err := c.Start(process); err != nil { + return err + } + if process.Init { + return c.exec() + } + return nil +} + +func (c *linuxContainer) Exec() error { + c.m.Lock() + defer c.m.Unlock() + return c.exec() +} + +func (c *linuxContainer) exec() error { + path := filepath.Join(c.root, execFifoFilename) + pid := c.initProcess.pid() + blockingFifoOpenCh := awaitFifoOpen(path) + for { + select { + case result := <-blockingFifoOpenCh: + return handleFifoResult(result) + + case <-time.After(time.Millisecond * 100): + stat, err := system.Stat(pid) + if err != nil || stat.State == system.Zombie { + // could be because process started, ran, and completed between our 100ms timeout and our system.Stat() check. + // see if the fifo exists and has data (with a non-blocking open, which will succeed if the writing process is complete). + if err := handleFifoResult(fifoOpen(path, false)); err != nil { + return errors.New("container process is already dead") + } + return nil + } + } + } +} + +func readFromExecFifo(execFifo io.Reader) error { + data, err := ioutil.ReadAll(execFifo) + if err != nil { + return err + } + if len(data) <= 0 { + return errors.New("cannot start an already running container") + } + return nil +} + +func awaitFifoOpen(path string) <-chan openResult { + fifoOpened := make(chan openResult) + go func() { + result := fifoOpen(path, true) + fifoOpened <- result + }() + return fifoOpened +} + +func fifoOpen(path string, block bool) openResult { + flags := os.O_RDONLY + if !block { + flags |= unix.O_NONBLOCK + } + f, err := os.OpenFile(path, flags, 0) + if err != nil { + return openResult{err: newSystemErrorWithCause(err, "open exec fifo for reading")} + } + return openResult{file: f} +} + +func handleFifoResult(result openResult) error { + if result.err != nil { + return result.err + } + f := result.file + defer f.Close() + if err := readFromExecFifo(f); err != nil { + return err + } + return os.Remove(f.Name()) +} + +type openResult struct { + file *os.File + err error +} + +func (c *linuxContainer) start(process *Process) error { + parent, err := c.newParentProcess(process) + if err != nil { + return newSystemErrorWithCause(err, "creating new parent process") + } + parent.forwardChildLogs() + if err := parent.start(); err != nil { + return newSystemErrorWithCause(err, "starting container process") + } + + if process.Init { + if c.config.Hooks != nil { + s, err := c.currentOCIState() + if err != nil { + return err + } + + if err := c.config.Hooks[configs.Poststart].RunHooks(s); err != nil { + if err := ignoreTerminateErrors(parent.terminate()); err != nil { + logrus.Warn(errorsf.Wrapf(err, "Running Poststart hook")) + } + return err + } + } + } + return nil +} + +func (c *linuxContainer) Signal(s os.Signal, all bool) error { + c.m.Lock() + defer c.m.Unlock() + status, err := c.currentStatus() + if err != nil { + return err + } + if all { + // for systemd cgroup, the unit's cgroup path will be auto removed if container's all processes exited + if status == Stopped && !c.cgroupManager.Exists() { + return nil + } + return signalAllProcesses(c.cgroupManager, s) + } + // to avoid a PID reuse attack + if status == Running || status == Created || status == Paused { + if err := c.initProcess.signal(s); err != nil { + return newSystemErrorWithCause(err, "signaling init process") + } + return nil + } + return newGenericError(errors.New("container not running"), ContainerNotRunning) +} + +func (c *linuxContainer) createExecFifo() error { + rootuid, err := c.Config().HostRootUID() + if err != nil { + return err + } + rootgid, err := c.Config().HostRootGID() + if err != nil { + return err + } + + fifoName := filepath.Join(c.root, execFifoFilename) + if _, err := os.Stat(fifoName); err == nil { + return fmt.Errorf("exec fifo %s already exists", fifoName) + } + oldMask := unix.Umask(0000) + if err := unix.Mkfifo(fifoName, 0622); err != nil { + unix.Umask(oldMask) + return err + } + unix.Umask(oldMask) + return os.Chown(fifoName, rootuid, rootgid) +} + +func (c *linuxContainer) deleteExecFifo() { + fifoName := filepath.Join(c.root, execFifoFilename) + os.Remove(fifoName) +} + +// includeExecFifo opens the container's execfifo as a pathfd, so that the +// container cannot access the statedir (and the FIFO itself remains +// un-opened). It then adds the FifoFd to the given exec.Cmd as an inherited +// fd, with _LIBCONTAINER_FIFOFD set to its fd number. +func (c *linuxContainer) includeExecFifo(cmd *exec.Cmd) error { + fifoName := filepath.Join(c.root, execFifoFilename) + fifoFd, err := unix.Open(fifoName, unix.O_PATH|unix.O_CLOEXEC, 0) + if err != nil { + return err + } + + cmd.ExtraFiles = append(cmd.ExtraFiles, os.NewFile(uintptr(fifoFd), fifoName)) + cmd.Env = append(cmd.Env, + "_LIBCONTAINER_FIFOFD="+strconv.Itoa(stdioFdCount+len(cmd.ExtraFiles)-1)) + return nil +} + +func (c *linuxContainer) newParentProcess(p *Process) (parentProcess, error) { + parentInitPipe, childInitPipe, err := utils.NewSockPair("init") + if err != nil { + return nil, newSystemErrorWithCause(err, "creating new init pipe") + } + messageSockPair := filePair{parentInitPipe, childInitPipe} + + parentLogPipe, childLogPipe, err := os.Pipe() + if err != nil { + return nil, fmt.Errorf("Unable to create the log pipe: %s", err) + } + logFilePair := filePair{parentLogPipe, childLogPipe} + + cmd := c.commandTemplate(p, childInitPipe, childLogPipe) + if !p.Init { + return c.newSetnsProcess(p, cmd, messageSockPair, logFilePair) + } + + // We only set up fifoFd if we're not doing a `runc exec`. The historic + // reason for this is that previously we would pass a dirfd that allowed + // for container rootfs escape (and not doing it in `runc exec` avoided + // that problem), but we no longer do that. However, there's no need to do + // this for `runc exec` so we just keep it this way to be safe. + if err := c.includeExecFifo(cmd); err != nil { + return nil, newSystemErrorWithCause(err, "including execfifo in cmd.Exec setup") + } + return c.newInitProcess(p, cmd, messageSockPair, logFilePair) +} + +func (c *linuxContainer) commandTemplate(p *Process, childInitPipe *os.File, childLogPipe *os.File) *exec.Cmd { + cmd := exec.Command(c.initPath, c.initArgs[1:]...) + cmd.Args[0] = c.initArgs[0] + cmd.Stdin = p.Stdin + cmd.Stdout = p.Stdout + cmd.Stderr = p.Stderr + cmd.Dir = c.config.Rootfs + if cmd.SysProcAttr == nil { + cmd.SysProcAttr = &unix.SysProcAttr{} + } + cmd.Env = append(cmd.Env, "GOMAXPROCS="+os.Getenv("GOMAXPROCS")) + cmd.ExtraFiles = append(cmd.ExtraFiles, p.ExtraFiles...) + if p.ConsoleSocket != nil { + cmd.ExtraFiles = append(cmd.ExtraFiles, p.ConsoleSocket) + cmd.Env = append(cmd.Env, + "_LIBCONTAINER_CONSOLE="+strconv.Itoa(stdioFdCount+len(cmd.ExtraFiles)-1), + ) + } + cmd.ExtraFiles = append(cmd.ExtraFiles, childInitPipe) + cmd.Env = append(cmd.Env, + "_LIBCONTAINER_INITPIPE="+strconv.Itoa(stdioFdCount+len(cmd.ExtraFiles)-1), + "_LIBCONTAINER_STATEDIR="+c.root, + ) + + cmd.ExtraFiles = append(cmd.ExtraFiles, childLogPipe) + cmd.Env = append(cmd.Env, + "_LIBCONTAINER_LOGPIPE="+strconv.Itoa(stdioFdCount+len(cmd.ExtraFiles)-1), + "_LIBCONTAINER_LOGLEVEL="+p.LogLevel, + ) + + // NOTE: when running a container with no PID namespace and the parent process spawning the container is + // PID1 the pdeathsig is being delivered to the container's init process by the kernel for some reason + // even with the parent still running. + if c.config.ParentDeathSignal > 0 { + cmd.SysProcAttr.Pdeathsig = unix.Signal(c.config.ParentDeathSignal) + } + return cmd +} + +func (c *linuxContainer) newInitProcess(p *Process, cmd *exec.Cmd, messageSockPair, logFilePair filePair) (*initProcess, error) { + cmd.Env = append(cmd.Env, "_LIBCONTAINER_INITTYPE="+string(initStandard)) + nsMaps := make(map[configs.NamespaceType]string) + for _, ns := range c.config.Namespaces { + if ns.Path != "" { + nsMaps[ns.Type] = ns.Path + } + } + _, sharePidns := nsMaps[configs.NEWPID] + data, err := c.bootstrapData(c.config.Namespaces.CloneFlags(), nsMaps) + if err != nil { + return nil, err + } + init := &initProcess{ + cmd: cmd, + messageSockPair: messageSockPair, + logFilePair: logFilePair, + manager: c.cgroupManager, + intelRdtManager: c.intelRdtManager, + config: c.newInitConfig(p), + container: c, + process: p, + bootstrapData: data, + sharePidns: sharePidns, + } + c.initProcess = init + return init, nil +} + +func (c *linuxContainer) newSetnsProcess(p *Process, cmd *exec.Cmd, messageSockPair, logFilePair filePair) (*setnsProcess, error) { + cmd.Env = append(cmd.Env, "_LIBCONTAINER_INITTYPE="+string(initSetns)) + state, err := c.currentState() + if err != nil { + return nil, newSystemErrorWithCause(err, "getting container's current state") + } + // for setns process, we don't have to set cloneflags as the process namespaces + // will only be set via setns syscall + data, err := c.bootstrapData(0, state.NamespacePaths) + if err != nil { + return nil, err + } + return &setnsProcess{ + cmd: cmd, + cgroupPaths: state.CgroupPaths, + rootlessCgroups: c.config.RootlessCgroups, + intelRdtPath: state.IntelRdtPath, + messageSockPair: messageSockPair, + logFilePair: logFilePair, + config: c.newInitConfig(p), + process: p, + bootstrapData: data, + initProcessPid: state.InitProcessPid, + }, nil +} + +func (c *linuxContainer) newInitConfig(process *Process) *initConfig { + cfg := &initConfig{ + Config: c.config, + Args: process.Args, + Env: process.Env, + User: process.User, + AdditionalGroups: process.AdditionalGroups, + Cwd: process.Cwd, + Capabilities: process.Capabilities, + PassedFilesCount: len(process.ExtraFiles), + ContainerId: c.ID(), + NoNewPrivileges: c.config.NoNewPrivileges, + RootlessEUID: c.config.RootlessEUID, + RootlessCgroups: c.config.RootlessCgroups, + AppArmorProfile: c.config.AppArmorProfile, + ProcessLabel: c.config.ProcessLabel, + Rlimits: c.config.Rlimits, + } + if process.NoNewPrivileges != nil { + cfg.NoNewPrivileges = *process.NoNewPrivileges + } + if process.AppArmorProfile != "" { + cfg.AppArmorProfile = process.AppArmorProfile + } + if process.Label != "" { + cfg.ProcessLabel = process.Label + } + if len(process.Rlimits) > 0 { + cfg.Rlimits = process.Rlimits + } + cfg.CreateConsole = process.ConsoleSocket != nil + cfg.ConsoleWidth = process.ConsoleWidth + cfg.ConsoleHeight = process.ConsoleHeight + return cfg +} + +func (c *linuxContainer) Destroy() error { + c.m.Lock() + defer c.m.Unlock() + return c.state.destroy() +} + +func (c *linuxContainer) Pause() error { + c.m.Lock() + defer c.m.Unlock() + status, err := c.currentStatus() + if err != nil { + return err + } + switch status { + case Running, Created: + if err := c.cgroupManager.Freeze(configs.Frozen); err != nil { + return err + } + return c.state.transition(&pausedState{ + c: c, + }) + } + return newGenericError(fmt.Errorf("container not running or created: %s", status), ContainerNotRunning) +} + +func (c *linuxContainer) Resume() error { + c.m.Lock() + defer c.m.Unlock() + status, err := c.currentStatus() + if err != nil { + return err + } + if status != Paused { + return newGenericError(fmt.Errorf("container not paused"), ContainerNotPaused) + } + if err := c.cgroupManager.Freeze(configs.Thawed); err != nil { + return err + } + return c.state.transition(&runningState{ + c: c, + }) +} + +func (c *linuxContainer) NotifyOOM() (<-chan struct{}, error) { + // XXX(cyphar): This requires cgroups. + if c.config.RootlessCgroups { + logrus.Warn("getting OOM notifications may fail if you don't have the full access to cgroups") + } + path := c.cgroupManager.Path("memory") + if cgroups.IsCgroup2UnifiedMode() { + return notifyOnOOMV2(path) + } + return notifyOnOOM(path) +} + +func (c *linuxContainer) NotifyMemoryPressure(level PressureLevel) (<-chan struct{}, error) { + // XXX(cyphar): This requires cgroups. + if c.config.RootlessCgroups { + logrus.Warn("getting memory pressure notifications may fail if you don't have the full access to cgroups") + } + return notifyMemoryPressure(c.cgroupManager.Path("memory"), level) +} + +var criuFeatures *criurpc.CriuFeatures + +func (c *linuxContainer) checkCriuFeatures(criuOpts *CriuOpts, rpcOpts *criurpc.CriuOpts, criuFeat *criurpc.CriuFeatures) error { + + t := criurpc.CriuReqType_FEATURE_CHECK + + // make sure the features we are looking for are really not from + // some previous check + criuFeatures = nil + + req := &criurpc.CriuReq{ + Type: &t, + // Theoretically this should not be necessary but CRIU + // segfaults if Opts is empty. + // Fixed in CRIU 2.12 + Opts: rpcOpts, + Features: criuFeat, + } + + err := c.criuSwrk(nil, req, criuOpts, nil) + if err != nil { + logrus.Debugf("%s", err) + return errors.New("CRIU feature check failed") + } + + logrus.Debugf("Feature check says: %s", criuFeatures) + missingFeatures := false + + // The outer if checks if the fields actually exist + if (criuFeat.MemTrack != nil) && + (criuFeatures.MemTrack != nil) { + // The inner if checks if they are set to true + if *criuFeat.MemTrack && !*criuFeatures.MemTrack { + missingFeatures = true + logrus.Debugf("CRIU does not support MemTrack") + } + } + + // This needs to be repeated for every new feature check. + // Is there a way to put this in a function. Reflection? + if (criuFeat.LazyPages != nil) && + (criuFeatures.LazyPages != nil) { + if *criuFeat.LazyPages && !*criuFeatures.LazyPages { + missingFeatures = true + logrus.Debugf("CRIU does not support LazyPages") + } + } + + if missingFeatures { + return errors.New("CRIU is missing features") + } + + return nil +} + +func compareCriuVersion(criuVersion int, minVersion int) error { + // simple function to perform the actual version compare + if criuVersion < minVersion { + return fmt.Errorf("CRIU version %d must be %d or higher", criuVersion, minVersion) + } + + return nil +} + +// checkCriuVersion checks Criu version greater than or equal to minVersion +func (c *linuxContainer) checkCriuVersion(minVersion int) error { + + // If the version of criu has already been determined there is no need + // to ask criu for the version again. Use the value from c.criuVersion. + if c.criuVersion != 0 { + return compareCriuVersion(c.criuVersion, minVersion) + } + + criu := criu.MakeCriu() + criu.SetCriuPath(c.criuPath) + var err error + c.criuVersion, err = criu.GetCriuVersion() + if err != nil { + return fmt.Errorf("CRIU version check failed: %s", err) + } + + return compareCriuVersion(c.criuVersion, minVersion) +} + +const descriptorsFilename = "descriptors.json" + +func (c *linuxContainer) addCriuDumpMount(req *criurpc.CriuReq, m *configs.Mount) { + mountDest := strings.TrimPrefix(m.Destination, c.config.Rootfs) + extMnt := &criurpc.ExtMountMap{ + Key: proto.String(mountDest), + Val: proto.String(mountDest), + } + req.Opts.ExtMnt = append(req.Opts.ExtMnt, extMnt) +} + +func (c *linuxContainer) addMaskPaths(req *criurpc.CriuReq) error { + for _, path := range c.config.MaskPaths { + fi, err := os.Stat(fmt.Sprintf("/proc/%d/root/%s", c.initProcess.pid(), path)) + if err != nil { + if os.IsNotExist(err) { + continue + } + return err + } + if fi.IsDir() { + continue + } + + extMnt := &criurpc.ExtMountMap{ + Key: proto.String(path), + Val: proto.String("/dev/null"), + } + req.Opts.ExtMnt = append(req.Opts.ExtMnt, extMnt) + } + return nil +} + +func (c *linuxContainer) handleCriuConfigurationFile(rpcOpts *criurpc.CriuOpts) { + // CRIU will evaluate a configuration starting with release 3.11. + // Settings in the configuration file will overwrite RPC settings. + // Look for annotations. The annotation 'org.criu.config' + // specifies if CRIU should use a different, container specific + // configuration file. + _, annotations := utils.Annotations(c.config.Labels) + configFile, exists := annotations["org.criu.config"] + if exists { + // If the annotation 'org.criu.config' exists and is set + // to a non-empty string, tell CRIU to use that as a + // configuration file. If the file does not exist, CRIU + // will just ignore it. + if configFile != "" { + rpcOpts.ConfigFile = proto.String(configFile) + } + // If 'org.criu.config' exists and is set to an empty + // string, a runc specific CRIU configuration file will + // be not set at all. + } else { + // If the mentioned annotation has not been found, specify + // a default CRIU configuration file. + rpcOpts.ConfigFile = proto.String("/etc/criu/runc.conf") + } +} + +func (c *linuxContainer) criuSupportsExtNS(t configs.NamespaceType) bool { + var minVersion int + switch t { + case configs.NEWNET: + // CRIU supports different external namespace with different released CRIU versions. + // For network namespaces to work we need at least criu 3.11.0 => 31100. + minVersion = 31100 + case configs.NEWPID: + // For PID namespaces criu 31500 is needed. + minVersion = 31500 + default: + return false + } + return c.checkCriuVersion(minVersion) == nil +} + +func criuNsToKey(t configs.NamespaceType) string { + return "extRoot" + strings.Title(configs.NsName(t)) + "NS" +} + +func (c *linuxContainer) handleCheckpointingExternalNamespaces(rpcOpts *criurpc.CriuOpts, t configs.NamespaceType) error { + if !c.criuSupportsExtNS(t) { + return nil + } + + nsPath := c.config.Namespaces.PathOf(t) + if nsPath == "" { + return nil + } + // CRIU expects the information about an external namespace + // like this: --external []: + // This is always 'extRootNS'. + var ns unix.Stat_t + if err := unix.Stat(nsPath, &ns); err != nil { + return err + } + criuExternal := fmt.Sprintf("%s[%d]:%s", configs.NsName(t), ns.Ino, criuNsToKey(t)) + rpcOpts.External = append(rpcOpts.External, criuExternal) + + return nil +} + +func (c *linuxContainer) handleRestoringNamespaces(rpcOpts *criurpc.CriuOpts, extraFiles *[]*os.File) error { + for _, ns := range c.config.Namespaces { + switch ns.Type { + case configs.NEWNET, configs.NEWPID: + // If the container is running in a network or PID namespace and has + // a path to the network or PID namespace configured, we will dump + // that network or PID namespace as an external namespace and we + // will expect that the namespace exists during restore. + // This basically means that CRIU will ignore the namespace + // and expect it to be setup correctly. + if err := c.handleRestoringExternalNamespaces(rpcOpts, extraFiles, ns.Type); err != nil { + return err + } + default: + // For all other namespaces except NET and PID CRIU has + // a simpler way of joining the existing namespace if set + nsPath := c.config.Namespaces.PathOf(ns.Type) + if nsPath == "" { + continue + } + if ns.Type == configs.NEWCGROUP { + // CRIU has no code to handle NEWCGROUP + return fmt.Errorf("Do not know how to handle namespace %v", ns.Type) + } + // CRIU has code to handle NEWTIME, but it does not seem to be defined in runc + + // CRIU will issue a warning for NEWUSER: + // criu/namespaces.c: 'join-ns with user-namespace is not fully tested and dangerous' + rpcOpts.JoinNs = append(rpcOpts.JoinNs, &criurpc.JoinNamespace{ + Ns: proto.String(configs.NsName(ns.Type)), + NsFile: proto.String(nsPath), + }) + } + } + + return nil +} + +func (c *linuxContainer) handleRestoringExternalNamespaces(rpcOpts *criurpc.CriuOpts, extraFiles *[]*os.File, t configs.NamespaceType) error { + if !c.criuSupportsExtNS(t) { + return nil + } + + nsPath := c.config.Namespaces.PathOf(t) + if nsPath == "" { + return nil + } + // CRIU wants the information about an existing namespace + // like this: --inherit-fd fd[]: + // The needs to be the same as during checkpointing. + // We are always using 'extRootNS' as the key in this. + nsFd, err := os.Open(nsPath) + if err != nil { + logrus.Errorf("If a specific network namespace is defined it must exist: %s", err) + return fmt.Errorf("Requested network namespace %v does not exist", nsPath) + } + inheritFd := &criurpc.InheritFd{ + Key: proto.String(criuNsToKey(t)), + // The offset of four is necessary because 0, 1, 2 and 3 are + // already used by stdin, stdout, stderr, 'criu swrk' socket. + Fd: proto.Int32(int32(4 + len(*extraFiles))), + } + rpcOpts.InheritFd = append(rpcOpts.InheritFd, inheritFd) + // All open FDs need to be transferred to CRIU via extraFiles + *extraFiles = append(*extraFiles, nsFd) + + return nil +} + +func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error { + c.m.Lock() + defer c.m.Unlock() + + // Checkpoint is unlikely to work if os.Geteuid() != 0 || system.RunningInUserNS(). + // (CLI prints a warning) + // TODO(avagin): Figure out how to make this work nicely. CRIU 2.0 has + // support for doing unprivileged dumps, but the setup of + // rootless containers might make this complicated. + + // We are relying on the CRIU version RPC which was introduced with CRIU 3.0.0 + if err := c.checkCriuVersion(30000); err != nil { + return err + } + + if criuOpts.ImagesDirectory == "" { + return errors.New("invalid directory to save checkpoint") + } + + // Since a container can be C/R'ed multiple times, + // the checkpoint directory may already exist. + if err := os.Mkdir(criuOpts.ImagesDirectory, 0700); err != nil && !os.IsExist(err) { + return err + } + + if criuOpts.WorkDirectory == "" { + criuOpts.WorkDirectory = filepath.Join(c.root, "criu.work") + } + + if err := os.Mkdir(criuOpts.WorkDirectory, 0700); err != nil && !os.IsExist(err) { + return err + } + + workDir, err := os.Open(criuOpts.WorkDirectory) + if err != nil { + return err + } + defer workDir.Close() + + imageDir, err := os.Open(criuOpts.ImagesDirectory) + if err != nil { + return err + } + defer imageDir.Close() + + rpcOpts := criurpc.CriuOpts{ + ImagesDirFd: proto.Int32(int32(imageDir.Fd())), + WorkDirFd: proto.Int32(int32(workDir.Fd())), + LogLevel: proto.Int32(4), + LogFile: proto.String("dump.log"), + Root: proto.String(c.config.Rootfs), + ManageCgroups: proto.Bool(true), + NotifyScripts: proto.Bool(true), + Pid: proto.Int32(int32(c.initProcess.pid())), + ShellJob: proto.Bool(criuOpts.ShellJob), + LeaveRunning: proto.Bool(criuOpts.LeaveRunning), + TcpEstablished: proto.Bool(criuOpts.TcpEstablished), + ExtUnixSk: proto.Bool(criuOpts.ExternalUnixConnections), + FileLocks: proto.Bool(criuOpts.FileLocks), + EmptyNs: proto.Uint32(criuOpts.EmptyNs), + OrphanPtsMaster: proto.Bool(true), + AutoDedup: proto.Bool(criuOpts.AutoDedup), + LazyPages: proto.Bool(criuOpts.LazyPages), + } + + c.handleCriuConfigurationFile(&rpcOpts) + + // If the container is running in a network namespace and has + // a path to the network namespace configured, we will dump + // that network namespace as an external namespace and we + // will expect that the namespace exists during restore. + // This basically means that CRIU will ignore the namespace + // and expect to be setup correctly. + if err := c.handleCheckpointingExternalNamespaces(&rpcOpts, configs.NEWNET); err != nil { + return err + } + + // Same for possible external PID namespaces + if err := c.handleCheckpointingExternalNamespaces(&rpcOpts, configs.NEWPID); err != nil { + return err + } + + // CRIU can use cgroup freezer; when rpcOpts.FreezeCgroup + // is not set, CRIU uses ptrace() to pause the processes. + // Note cgroup v2 freezer is only supported since CRIU release 3.14. + if !cgroups.IsCgroup2UnifiedMode() || c.checkCriuVersion(31400) == nil { + if fcg := c.cgroupManager.Path("freezer"); fcg != "" { + rpcOpts.FreezeCgroup = proto.String(fcg) + } + } + + // append optional criu opts, e.g., page-server and port + if criuOpts.PageServer.Address != "" && criuOpts.PageServer.Port != 0 { + rpcOpts.Ps = &criurpc.CriuPageServerInfo{ + Address: proto.String(criuOpts.PageServer.Address), + Port: proto.Int32(criuOpts.PageServer.Port), + } + } + + //pre-dump may need parentImage param to complete iterative migration + if criuOpts.ParentImage != "" { + rpcOpts.ParentImg = proto.String(criuOpts.ParentImage) + rpcOpts.TrackMem = proto.Bool(true) + } + + // append optional manage cgroups mode + if criuOpts.ManageCgroupsMode != 0 { + mode := criurpc.CriuCgMode(criuOpts.ManageCgroupsMode) + rpcOpts.ManageCgroupsMode = &mode + } + + var t criurpc.CriuReqType + if criuOpts.PreDump { + feat := criurpc.CriuFeatures{ + MemTrack: proto.Bool(true), + } + + if err := c.checkCriuFeatures(criuOpts, &rpcOpts, &feat); err != nil { + return err + } + + t = criurpc.CriuReqType_PRE_DUMP + } else { + t = criurpc.CriuReqType_DUMP + } + + if criuOpts.LazyPages { + // lazy migration requested; check if criu supports it + feat := criurpc.CriuFeatures{ + LazyPages: proto.Bool(true), + } + if err := c.checkCriuFeatures(criuOpts, &rpcOpts, &feat); err != nil { + return err + } + + if fd := criuOpts.StatusFd; fd != -1 { + // check that the FD is valid + flags, err := unix.FcntlInt(uintptr(fd), unix.F_GETFL, 0) + if err != nil { + return fmt.Errorf("invalid --status-fd argument %d: %w", fd, err) + } + // and writable + if flags&unix.O_WRONLY == 0 { + return fmt.Errorf("invalid --status-fd argument %d: not writable", fd) + } + + if c.checkCriuVersion(31500) != nil { + // For criu 3.15+, use notifications (see case "status-ready" + // in criuNotifications). Otherwise, rely on criu status fd. + rpcOpts.StatusFd = proto.Int32(int32(fd)) + } + } + } + + req := &criurpc.CriuReq{ + Type: &t, + Opts: &rpcOpts, + } + + // no need to dump all this in pre-dump + if !criuOpts.PreDump { + hasCgroupns := c.config.Namespaces.Contains(configs.NEWCGROUP) + for _, m := range c.config.Mounts { + switch m.Device { + case "bind": + c.addCriuDumpMount(req, m) + case "cgroup": + if cgroups.IsCgroup2UnifiedMode() || hasCgroupns { + // real mount(s) + continue + } + // a set of "external" bind mounts + binds, err := getCgroupMounts(m) + if err != nil { + return err + } + for _, b := range binds { + c.addCriuDumpMount(req, b) + } + } + } + + if err := c.addMaskPaths(req); err != nil { + return err + } + + for _, node := range c.config.Devices { + m := &configs.Mount{Destination: node.Path, Source: node.Path} + c.addCriuDumpMount(req, m) + } + + // Write the FD info to a file in the image directory + fdsJSON, err := json.Marshal(c.initProcess.externalDescriptors()) + if err != nil { + return err + } + + err = ioutil.WriteFile(filepath.Join(criuOpts.ImagesDirectory, descriptorsFilename), fdsJSON, 0600) + if err != nil { + return err + } + } + + err = c.criuSwrk(nil, req, criuOpts, nil) + if err != nil { + return err + } + return nil +} + +func (c *linuxContainer) addCriuRestoreMount(req *criurpc.CriuReq, m *configs.Mount) { + mountDest := strings.TrimPrefix(m.Destination, c.config.Rootfs) + extMnt := &criurpc.ExtMountMap{ + Key: proto.String(mountDest), + Val: proto.String(m.Source), + } + req.Opts.ExtMnt = append(req.Opts.ExtMnt, extMnt) +} + +func (c *linuxContainer) restoreNetwork(req *criurpc.CriuReq, criuOpts *CriuOpts) { + for _, iface := range c.config.Networks { + switch iface.Type { + case "veth": + veth := new(criurpc.CriuVethPair) + veth.IfOut = proto.String(iface.HostInterfaceName) + veth.IfIn = proto.String(iface.Name) + req.Opts.Veths = append(req.Opts.Veths, veth) + case "loopback": + // Do nothing + } + } + for _, i := range criuOpts.VethPairs { + veth := new(criurpc.CriuVethPair) + veth.IfOut = proto.String(i.HostInterfaceName) + veth.IfIn = proto.String(i.ContainerInterfaceName) + req.Opts.Veths = append(req.Opts.Veths, veth) + } +} + +// makeCriuRestoreMountpoints makes the actual mountpoints for the +// restore using CRIU. This function is inspired from the code in +// rootfs_linux.go +func (c *linuxContainer) makeCriuRestoreMountpoints(m *configs.Mount) error { + switch m.Device { + case "cgroup": + // No mount point(s) need to be created: + // + // * for v1, mount points are saved by CRIU because + // /sys/fs/cgroup is a tmpfs mount + // + // * for v2, /sys/fs/cgroup is a real mount, but + // the mountpoint appears as soon as /sys is mounted + return nil + case "bind": + // The prepareBindMount() function checks if source + // exists. So it cannot be used for other filesystem types. + if err := prepareBindMount(m, c.config.Rootfs); err != nil { + return err + } + default: + // for all other filesystems just create the mountpoints + dest, err := securejoin.SecureJoin(c.config.Rootfs, m.Destination) + if err != nil { + return err + } + if err := checkProcMount(c.config.Rootfs, dest, ""); err != nil { + return err + } + m.Destination = dest + if err := os.MkdirAll(dest, 0755); err != nil { + return err + } + } + return nil +} + +// isPathInPrefixList is a small function for CRIU restore to make sure +// mountpoints, which are on a tmpfs, are not created in the roofs +func isPathInPrefixList(path string, prefix []string) bool { + for _, p := range prefix { + if strings.HasPrefix(path, p+"/") { + return true + } + } + return false +} + +// prepareCriuRestoreMounts tries to set up the rootfs of the +// container to be restored in the same way runc does it for +// initial container creation. Even for a read-only rootfs container +// runc modifies the rootfs to add mountpoints which do not exist. +// This function also creates missing mountpoints as long as they +// are not on top of a tmpfs, as CRIU will restore tmpfs content anyway. +func (c *linuxContainer) prepareCriuRestoreMounts(mounts []*configs.Mount) error { + // First get a list of a all tmpfs mounts + tmpfs := []string{} + for _, m := range mounts { + switch m.Device { + case "tmpfs": + tmpfs = append(tmpfs, m.Destination) + } + } + // Now go through all mounts and create the mountpoints + // if the mountpoints are not on a tmpfs, as CRIU will + // restore the complete tmpfs content from its checkpoint. + for _, m := range mounts { + if !isPathInPrefixList(m.Destination, tmpfs) { + if err := c.makeCriuRestoreMountpoints(m); err != nil { + return err + } + } + } + return nil +} + +func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error { + c.m.Lock() + defer c.m.Unlock() + + var extraFiles []*os.File + + // Restore is unlikely to work if os.Geteuid() != 0 || system.RunningInUserNS(). + // (CLI prints a warning) + // TODO(avagin): Figure out how to make this work nicely. CRIU doesn't have + // support for unprivileged restore at the moment. + + // We are relying on the CRIU version RPC which was introduced with CRIU 3.0.0 + if err := c.checkCriuVersion(30000); err != nil { + return err + } + if criuOpts.WorkDirectory == "" { + criuOpts.WorkDirectory = filepath.Join(c.root, "criu.work") + } + // Since a container can be C/R'ed multiple times, + // the work directory may already exist. + if err := os.Mkdir(criuOpts.WorkDirectory, 0700); err != nil && !os.IsExist(err) { + return err + } + workDir, err := os.Open(criuOpts.WorkDirectory) + if err != nil { + return err + } + defer workDir.Close() + if criuOpts.ImagesDirectory == "" { + return errors.New("invalid directory to restore checkpoint") + } + imageDir, err := os.Open(criuOpts.ImagesDirectory) + if err != nil { + return err + } + defer imageDir.Close() + // CRIU has a few requirements for a root directory: + // * it must be a mount point + // * its parent must not be overmounted + // c.config.Rootfs is bind-mounted to a temporary directory + // to satisfy these requirements. + root := filepath.Join(c.root, "criu-root") + if err := os.Mkdir(root, 0755); err != nil { + return err + } + defer os.Remove(root) + root, err = filepath.EvalSymlinks(root) + if err != nil { + return err + } + err = unix.Mount(c.config.Rootfs, root, "", unix.MS_BIND|unix.MS_REC, "") + if err != nil { + return err + } + defer unix.Unmount(root, unix.MNT_DETACH) + t := criurpc.CriuReqType_RESTORE + req := &criurpc.CriuReq{ + Type: &t, + Opts: &criurpc.CriuOpts{ + ImagesDirFd: proto.Int32(int32(imageDir.Fd())), + WorkDirFd: proto.Int32(int32(workDir.Fd())), + EvasiveDevices: proto.Bool(true), + LogLevel: proto.Int32(4), + LogFile: proto.String("restore.log"), + RstSibling: proto.Bool(true), + Root: proto.String(root), + ManageCgroups: proto.Bool(true), + NotifyScripts: proto.Bool(true), + ShellJob: proto.Bool(criuOpts.ShellJob), + ExtUnixSk: proto.Bool(criuOpts.ExternalUnixConnections), + TcpEstablished: proto.Bool(criuOpts.TcpEstablished), + FileLocks: proto.Bool(criuOpts.FileLocks), + EmptyNs: proto.Uint32(criuOpts.EmptyNs), + OrphanPtsMaster: proto.Bool(true), + AutoDedup: proto.Bool(criuOpts.AutoDedup), + LazyPages: proto.Bool(criuOpts.LazyPages), + }, + } + + c.handleCriuConfigurationFile(req.Opts) + + if err := c.handleRestoringNamespaces(req.Opts, &extraFiles); err != nil { + return err + } + + // This will modify the rootfs of the container in the same way runc + // modifies the container during initial creation. + if err := c.prepareCriuRestoreMounts(c.config.Mounts); err != nil { + return err + } + + hasCgroupns := c.config.Namespaces.Contains(configs.NEWCGROUP) + for _, m := range c.config.Mounts { + switch m.Device { + case "bind": + c.addCriuRestoreMount(req, m) + case "cgroup": + if cgroups.IsCgroup2UnifiedMode() || hasCgroupns { + continue + } + // cgroup v1 is a set of bind mounts, unless cgroupns is used + binds, err := getCgroupMounts(m) + if err != nil { + return err + } + for _, b := range binds { + c.addCriuRestoreMount(req, b) + } + } + } + + if len(c.config.MaskPaths) > 0 { + m := &configs.Mount{Destination: "/dev/null", Source: "/dev/null"} + c.addCriuRestoreMount(req, m) + } + + for _, node := range c.config.Devices { + m := &configs.Mount{Destination: node.Path, Source: node.Path} + c.addCriuRestoreMount(req, m) + } + + if criuOpts.EmptyNs&unix.CLONE_NEWNET == 0 { + c.restoreNetwork(req, criuOpts) + } + + // append optional manage cgroups mode + if criuOpts.ManageCgroupsMode != 0 { + mode := criurpc.CriuCgMode(criuOpts.ManageCgroupsMode) + req.Opts.ManageCgroupsMode = &mode + } + + var ( + fds []string + fdJSON []byte + ) + if fdJSON, err = ioutil.ReadFile(filepath.Join(criuOpts.ImagesDirectory, descriptorsFilename)); err != nil { + return err + } + + if err := json.Unmarshal(fdJSON, &fds); err != nil { + return err + } + for i := range fds { + if s := fds[i]; strings.Contains(s, "pipe:") { + inheritFd := new(criurpc.InheritFd) + inheritFd.Key = proto.String(s) + inheritFd.Fd = proto.Int32(int32(i)) + req.Opts.InheritFd = append(req.Opts.InheritFd, inheritFd) + } + } + err = c.criuSwrk(process, req, criuOpts, extraFiles) + + // Now that CRIU is done let's close all opened FDs CRIU needed. + for _, fd := range extraFiles { + fd.Close() + } + + return err +} + +func (c *linuxContainer) criuApplyCgroups(pid int, req *criurpc.CriuReq) error { + // need to apply cgroups only on restore + if req.GetType() != criurpc.CriuReqType_RESTORE { + return nil + } + + // XXX: Do we need to deal with this case? AFAIK criu still requires root. + if err := c.cgroupManager.Apply(pid); err != nil { + return err + } + + if err := c.cgroupManager.Set(c.config); err != nil { + return newSystemError(err) + } + + if cgroups.IsCgroup2UnifiedMode() { + return nil + } + // the stuff below is cgroupv1-specific + + path := fmt.Sprintf("/proc/%d/cgroup", pid) + cgroupsPaths, err := cgroups.ParseCgroupFile(path) + if err != nil { + return err + } + + for c, p := range cgroupsPaths { + cgroupRoot := &criurpc.CgroupRoot{ + Ctrl: proto.String(c), + Path: proto.String(p), + } + req.Opts.CgRoot = append(req.Opts.CgRoot, cgroupRoot) + } + + return nil +} + +func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts *CriuOpts, extraFiles []*os.File) error { + fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_SEQPACKET|unix.SOCK_CLOEXEC, 0) + if err != nil { + return err + } + + var logPath string + if opts != nil { + logPath = filepath.Join(opts.WorkDirectory, req.GetOpts().GetLogFile()) + } else { + // For the VERSION RPC 'opts' is set to 'nil' and therefore + // opts.WorkDirectory does not exist. Set logPath to "". + logPath = "" + } + criuClient := os.NewFile(uintptr(fds[0]), "criu-transport-client") + criuClientFileCon, err := net.FileConn(criuClient) + criuClient.Close() + if err != nil { + return err + } + + criuClientCon := criuClientFileCon.(*net.UnixConn) + defer criuClientCon.Close() + + criuServer := os.NewFile(uintptr(fds[1]), "criu-transport-server") + defer criuServer.Close() + + args := []string{"swrk", "3"} + if c.criuVersion != 0 { + // If the CRIU Version is still '0' then this is probably + // the initial CRIU run to detect the version. Skip it. + logrus.Debugf("Using CRIU %d at: %s", c.criuVersion, c.criuPath) + } + logrus.Debugf("Using CRIU with following args: %s", args) + cmd := exec.Command(c.criuPath, args...) + if process != nil { + cmd.Stdin = process.Stdin + cmd.Stdout = process.Stdout + cmd.Stderr = process.Stderr + } + cmd.ExtraFiles = append(cmd.ExtraFiles, criuServer) + if extraFiles != nil { + cmd.ExtraFiles = append(cmd.ExtraFiles, extraFiles...) + } + + if err := cmd.Start(); err != nil { + return err + } + // we close criuServer so that even if CRIU crashes or unexpectedly exits, runc will not hang. + criuServer.Close() + // cmd.Process will be replaced by a restored init. + criuProcess := cmd.Process + + var criuProcessState *os.ProcessState + defer func() { + if criuProcessState == nil { + criuClientCon.Close() + _, err := criuProcess.Wait() + if err != nil { + logrus.Warnf("wait on criuProcess returned %v", err) + } + } + }() + + if err := c.criuApplyCgroups(criuProcess.Pid, req); err != nil { + return err + } + + var extFds []string + if process != nil { + extFds, err = getPipeFds(criuProcess.Pid) + if err != nil { + return err + } + } + + logrus.Debugf("Using CRIU in %s mode", req.GetType().String()) + // In the case of criurpc.CriuReqType_FEATURE_CHECK req.GetOpts() + // should be empty. For older CRIU versions it still will be + // available but empty. criurpc.CriuReqType_VERSION actually + // has no req.GetOpts(). + if !(req.GetType() == criurpc.CriuReqType_FEATURE_CHECK || + req.GetType() == criurpc.CriuReqType_VERSION) { + + val := reflect.ValueOf(req.GetOpts()) + v := reflect.Indirect(val) + for i := 0; i < v.NumField(); i++ { + st := v.Type() + name := st.Field(i).Name + if strings.HasPrefix(name, "XXX_") { + continue + } + value := val.MethodByName("Get" + name).Call([]reflect.Value{}) + logrus.Debugf("CRIU option %s with value %v", name, value[0]) + } + } + data, err := proto.Marshal(req) + if err != nil { + return err + } + _, err = criuClientCon.Write(data) + if err != nil { + return err + } + + buf := make([]byte, 10*4096) + oob := make([]byte, 4096) + for { + n, oobn, _, _, err := criuClientCon.ReadMsgUnix(buf, oob) + if req.Opts != nil && req.Opts.StatusFd != nil { + // Close status_fd as soon as we got something back from criu, + // assuming it has consumed (reopened) it by this time. + // Otherwise it will might be left open forever and whoever + // is waiting on it will wait forever. + fd := int(*req.Opts.StatusFd) + _ = unix.Close(fd) + req.Opts.StatusFd = nil + } + if err != nil { + return err + } + if n == 0 { + return errors.New("unexpected EOF") + } + if n == len(buf) { + return errors.New("buffer is too small") + } + + resp := new(criurpc.CriuResp) + err = proto.Unmarshal(buf[:n], resp) + if err != nil { + return err + } + if !resp.GetSuccess() { + typeString := req.GetType().String() + return fmt.Errorf("criu failed: type %s errno %d\nlog file: %s", typeString, resp.GetCrErrno(), logPath) + } + + t := resp.GetType() + switch { + case t == criurpc.CriuReqType_FEATURE_CHECK: + logrus.Debugf("Feature check says: %s", resp) + criuFeatures = resp.GetFeatures() + case t == criurpc.CriuReqType_NOTIFY: + if err := c.criuNotifications(resp, process, cmd, opts, extFds, oob[:oobn]); err != nil { + return err + } + t = criurpc.CriuReqType_NOTIFY + req = &criurpc.CriuReq{ + Type: &t, + NotifySuccess: proto.Bool(true), + } + data, err = proto.Marshal(req) + if err != nil { + return err + } + _, err = criuClientCon.Write(data) + if err != nil { + return err + } + continue + case t == criurpc.CriuReqType_RESTORE: + case t == criurpc.CriuReqType_DUMP: + case t == criurpc.CriuReqType_PRE_DUMP: + default: + return fmt.Errorf("unable to parse the response %s", resp.String()) + } + + break + } + + criuClientCon.CloseWrite() + // cmd.Wait() waits cmd.goroutines which are used for proxying file descriptors. + // Here we want to wait only the CRIU process. + criuProcessState, err = criuProcess.Wait() + if err != nil { + return err + } + + // In pre-dump mode CRIU is in a loop and waits for + // the final DUMP command. + // The current runc pre-dump approach, however, is + // start criu in PRE_DUMP once for a single pre-dump + // and not the whole series of pre-dump, pre-dump, ...m, dump + // If we got the message CriuReqType_PRE_DUMP it means + // CRIU was successful and we need to forcefully stop CRIU + if !criuProcessState.Success() && *req.Type != criurpc.CriuReqType_PRE_DUMP { + return fmt.Errorf("criu failed: %s\nlog file: %s", criuProcessState.String(), logPath) + } + return nil +} + +// block any external network activity +func lockNetwork(config *configs.Config) error { + for _, config := range config.Networks { + strategy, err := getStrategy(config.Type) + if err != nil { + return err + } + + if err := strategy.detach(config); err != nil { + return err + } + } + return nil +} + +func unlockNetwork(config *configs.Config) error { + for _, config := range config.Networks { + strategy, err := getStrategy(config.Type) + if err != nil { + return err + } + if err = strategy.attach(config); err != nil { + return err + } + } + return nil +} + +func (c *linuxContainer) criuNotifications(resp *criurpc.CriuResp, process *Process, cmd *exec.Cmd, opts *CriuOpts, fds []string, oob []byte) error { + notify := resp.GetNotify() + if notify == nil { + return fmt.Errorf("invalid response: %s", resp.String()) + } + script := notify.GetScript() + logrus.Debugf("notify: %s\n", script) + switch script { + case "post-dump": + f, err := os.Create(filepath.Join(c.root, "checkpoint")) + if err != nil { + return err + } + f.Close() + case "network-unlock": + if err := unlockNetwork(c.config); err != nil { + return err + } + case "network-lock": + if err := lockNetwork(c.config); err != nil { + return err + } + case "setup-namespaces": + if c.config.Hooks != nil { + s, err := c.currentOCIState() + if err != nil { + return nil + } + s.Pid = int(notify.GetPid()) + + if err := c.config.Hooks[configs.Prestart].RunHooks(s); err != nil { + return err + } + if err := c.config.Hooks[configs.CreateRuntime].RunHooks(s); err != nil { + return err + } + } + case "post-restore": + pid := notify.GetPid() + + p, err := os.FindProcess(int(pid)) + if err != nil { + return err + } + cmd.Process = p + + r, err := newRestoredProcess(cmd, fds) + if err != nil { + return err + } + process.ops = r + if err := c.state.transition(&restoredState{ + imageDir: opts.ImagesDirectory, + c: c, + }); err != nil { + return err + } + // create a timestamp indicating when the restored checkpoint was started + c.created = time.Now().UTC() + if _, err := c.updateState(r); err != nil { + return err + } + if err := os.Remove(filepath.Join(c.root, "checkpoint")); err != nil { + if !os.IsNotExist(err) { + logrus.Error(err) + } + } + case "orphan-pts-master": + scm, err := unix.ParseSocketControlMessage(oob) + if err != nil { + return err + } + fds, err := unix.ParseUnixRights(&scm[0]) + if err != nil { + return err + } + + master := os.NewFile(uintptr(fds[0]), "orphan-pts-master") + defer master.Close() + + // While we can access console.master, using the API is a good idea. + if err := utils.SendFd(process.ConsoleSocket, master.Name(), master.Fd()); err != nil { + return err + } + case "status-ready": + if opts.StatusFd != -1 { + // write \0 to status fd to notify that lazy page server is ready + _, err := unix.Write(opts.StatusFd, []byte{0}) + if err != nil { + logrus.Warnf("can't write \\0 to status fd: %v", err) + } + _ = unix.Close(opts.StatusFd) + opts.StatusFd = -1 + } + } + return nil +} + +func (c *linuxContainer) updateState(process parentProcess) (*State, error) { + if process != nil { + c.initProcess = process + } + state, err := c.currentState() + if err != nil { + return nil, err + } + err = c.saveState(state) + if err != nil { + return nil, err + } + return state, nil +} + +func (c *linuxContainer) saveState(s *State) (retErr error) { + tmpFile, err := ioutil.TempFile(c.root, "state-") + if err != nil { + return err + } + + defer func() { + if retErr != nil { + tmpFile.Close() + os.Remove(tmpFile.Name()) + } + }() + + err = utils.WriteJSON(tmpFile, s) + if err != nil { + return err + } + err = tmpFile.Close() + if err != nil { + return err + } + + stateFilePath := filepath.Join(c.root, stateFilename) + return os.Rename(tmpFile.Name(), stateFilePath) +} + +func (c *linuxContainer) currentStatus() (Status, error) { + if err := c.refreshState(); err != nil { + return -1, err + } + return c.state.status(), nil +} + +// refreshState needs to be called to verify that the current state on the +// container is what is true. Because consumers of libcontainer can use it +// out of process we need to verify the container's status based on runtime +// information and not rely on our in process info. +func (c *linuxContainer) refreshState() error { + paused, err := c.isPaused() + if err != nil { + return err + } + if paused { + return c.state.transition(&pausedState{c: c}) + } + t := c.runType() + switch t { + case Created: + return c.state.transition(&createdState{c: c}) + case Running: + return c.state.transition(&runningState{c: c}) + } + return c.state.transition(&stoppedState{c: c}) +} + +func (c *linuxContainer) runType() Status { + if c.initProcess == nil { + return Stopped + } + pid := c.initProcess.pid() + stat, err := system.Stat(pid) + if err != nil { + return Stopped + } + if stat.StartTime != c.initProcessStartTime || stat.State == system.Zombie || stat.State == system.Dead { + return Stopped + } + // We'll create exec fifo and blocking on it after container is created, + // and delete it after start container. + if _, err := os.Stat(filepath.Join(c.root, execFifoFilename)); err == nil { + return Created + } + return Running +} + +func (c *linuxContainer) isPaused() (bool, error) { + state, err := c.cgroupManager.GetFreezerState() + if err != nil { + return false, err + } + return state == configs.Frozen, nil +} + +func (c *linuxContainer) currentState() (*State, error) { + var ( + startTime uint64 + externalDescriptors []string + pid = -1 + ) + if c.initProcess != nil { + pid = c.initProcess.pid() + startTime, _ = c.initProcess.startTime() + externalDescriptors = c.initProcess.externalDescriptors() + } + intelRdtPath, err := intelrdt.GetIntelRdtPath(c.ID()) + if err != nil { + intelRdtPath = "" + } + state := &State{ + BaseState: BaseState{ + ID: c.ID(), + Config: *c.config, + InitProcessPid: pid, + InitProcessStartTime: startTime, + Created: c.created, + }, + Rootless: c.config.RootlessEUID && c.config.RootlessCgroups, + CgroupPaths: c.cgroupManager.GetPaths(), + IntelRdtPath: intelRdtPath, + NamespacePaths: make(map[configs.NamespaceType]string), + ExternalDescriptors: externalDescriptors, + } + if pid > 0 { + for _, ns := range c.config.Namespaces { + state.NamespacePaths[ns.Type] = ns.GetPath(pid) + } + for _, nsType := range configs.NamespaceTypes() { + if !configs.IsNamespaceSupported(nsType) { + continue + } + if _, ok := state.NamespacePaths[nsType]; !ok { + ns := configs.Namespace{Type: nsType} + state.NamespacePaths[ns.Type] = ns.GetPath(pid) + } + } + } + return state, nil +} + +func (c *linuxContainer) currentOCIState() (*specs.State, error) { + bundle, annotations := utils.Annotations(c.config.Labels) + state := &specs.State{ + Version: specs.Version, + ID: c.ID(), + Bundle: bundle, + Annotations: annotations, + } + status, err := c.currentStatus() + if err != nil { + return nil, err + } + state.Status = specs.ContainerState(status.String()) + if status != Stopped { + if c.initProcess != nil { + state.Pid = c.initProcess.pid() + } + } + return state, nil +} + +// orderNamespacePaths sorts namespace paths into a list of paths that we +// can setns in order. +func (c *linuxContainer) orderNamespacePaths(namespaces map[configs.NamespaceType]string) ([]string, error) { + paths := []string{} + for _, ns := range configs.NamespaceTypes() { + + // Remove namespaces that we don't need to join. + if !c.config.Namespaces.Contains(ns) { + continue + } + + if p, ok := namespaces[ns]; ok && p != "" { + // check if the requested namespace is supported + if !configs.IsNamespaceSupported(ns) { + return nil, newSystemError(fmt.Errorf("namespace %s is not supported", ns)) + } + // only set to join this namespace if it exists + if _, err := os.Lstat(p); err != nil { + return nil, newSystemErrorWithCausef(err, "running lstat on namespace path %q", p) + } + // do not allow namespace path with comma as we use it to separate + // the namespace paths + if strings.ContainsRune(p, ',') { + return nil, newSystemError(fmt.Errorf("invalid path %s", p)) + } + paths = append(paths, fmt.Sprintf("%s:%s", configs.NsName(ns), p)) + } + + } + + return paths, nil +} + +func encodeIDMapping(idMap []configs.IDMap) ([]byte, error) { + data := bytes.NewBuffer(nil) + for _, im := range idMap { + line := fmt.Sprintf("%d %d %d\n", im.ContainerID, im.HostID, im.Size) + if _, err := data.WriteString(line); err != nil { + return nil, err + } + } + return data.Bytes(), nil +} + +// bootstrapData encodes the necessary data in netlink binary format +// as a io.Reader. +// Consumer can write the data to a bootstrap program +// such as one that uses nsenter package to bootstrap the container's +// init process correctly, i.e. with correct namespaces, uid/gid +// mapping etc. +func (c *linuxContainer) bootstrapData(cloneFlags uintptr, nsMaps map[configs.NamespaceType]string) (io.Reader, error) { + // create the netlink message + r := nl.NewNetlinkRequest(int(InitMsg), 0) + + // write cloneFlags + r.AddData(&Int32msg{ + Type: CloneFlagsAttr, + Value: uint32(cloneFlags), + }) + + // write custom namespace paths + if len(nsMaps) > 0 { + nsPaths, err := c.orderNamespacePaths(nsMaps) + if err != nil { + return nil, err + } + r.AddData(&Bytemsg{ + Type: NsPathsAttr, + Value: []byte(strings.Join(nsPaths, ",")), + }) + } + + // write namespace paths only when we are not joining an existing user ns + _, joinExistingUser := nsMaps[configs.NEWUSER] + if !joinExistingUser { + // write uid mappings + if len(c.config.UidMappings) > 0 { + if c.config.RootlessEUID && c.newuidmapPath != "" { + r.AddData(&Bytemsg{ + Type: UidmapPathAttr, + Value: []byte(c.newuidmapPath), + }) + } + b, err := encodeIDMapping(c.config.UidMappings) + if err != nil { + return nil, err + } + r.AddData(&Bytemsg{ + Type: UidmapAttr, + Value: b, + }) + } + + // write gid mappings + if len(c.config.GidMappings) > 0 { + b, err := encodeIDMapping(c.config.GidMappings) + if err != nil { + return nil, err + } + r.AddData(&Bytemsg{ + Type: GidmapAttr, + Value: b, + }) + if c.config.RootlessEUID && c.newgidmapPath != "" { + r.AddData(&Bytemsg{ + Type: GidmapPathAttr, + Value: []byte(c.newgidmapPath), + }) + } + if requiresRootOrMappingTool(c.config) { + r.AddData(&Boolmsg{ + Type: SetgroupAttr, + Value: true, + }) + } + } + } + + if c.config.OomScoreAdj != nil { + // write oom_score_adj + r.AddData(&Bytemsg{ + Type: OomScoreAdjAttr, + Value: []byte(strconv.Itoa(*c.config.OomScoreAdj)), + }) + } + + // write rootless + r.AddData(&Boolmsg{ + Type: RootlessEUIDAttr, + Value: c.config.RootlessEUID, + }) + + return bytes.NewReader(r.Serialize()), nil +} + +// ignoreTerminateErrors returns nil if the given err matches an error known +// to indicate that the terminate occurred successfully or err was nil, otherwise +// err is returned unaltered. +func ignoreTerminateErrors(err error) error { + if err == nil { + return nil + } + // terminate() might return an error from ether Kill or Wait. + // The (*Cmd).Wait documentation says: "If the command fails to run + // or doesn't complete successfully, the error is of type *ExitError". + // Filter out such errors (like "exit status 1" or "signal: killed"). + var exitErr *exec.ExitError + if errors.As(err, &exitErr) { + return nil + } + // TODO: use errors.Is(err, os.ErrProcessDone) here and + // remove "process already finished" string comparison below + // once go 1.16 is minimally supported version. + + s := err.Error() + if strings.Contains(s, "process already finished") || + strings.Contains(s, "Wait was already called") { + return nil + } + return err +} + +func requiresRootOrMappingTool(c *configs.Config) bool { + gidMap := []configs.IDMap{ + {ContainerID: 0, HostID: os.Getegid(), Size: 1}, + } + return !reflect.DeepEqual(c.GidMappings, gidMap) +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/criu_opts_linux.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/criu_opts_linux.go new file mode 100644 index 000000000000..11cbdb2db982 --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/criu_opts_linux.go @@ -0,0 +1,32 @@ +package libcontainer + +import criu "github.com/checkpoint-restore/go-criu/v4/rpc" + +type CriuPageServerInfo struct { + Address string // IP address of CRIU page server + Port int32 // port number of CRIU page server +} + +type VethPairName struct { + ContainerInterfaceName string + HostInterfaceName string +} + +type CriuOpts struct { + ImagesDirectory string // directory for storing image files + WorkDirectory string // directory to cd and write logs/pidfiles/stats to + ParentImage string // directory for storing parent image files in pre-dump and dump + LeaveRunning bool // leave container in running state after checkpoint + TcpEstablished bool // checkpoint/restore established TCP connections + ExternalUnixConnections bool // allow external unix connections + ShellJob bool // allow to dump and restore shell jobs + FileLocks bool // handle file locks, for safety + PreDump bool // call criu predump to perform iterative checkpoint + PageServer CriuPageServerInfo // allow to dump to criu page server + VethPairs []VethPairName // pass the veth to criu when restore + ManageCgroupsMode criu.CriuCgMode // dump or restore cgroup mode + EmptyNs uint32 // don't c/r properties for namespace from this mask + AutoDedup bool // auto deduplication for incremental dumps + LazyPages bool // restore memory pages lazily using userfaultfd + StatusFd int // fd for feedback when lazy server is ready +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/error.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/error.go new file mode 100644 index 000000000000..21a3789ba18d --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/error.go @@ -0,0 +1,70 @@ +package libcontainer + +import "io" + +// ErrorCode is the API error code type. +type ErrorCode int + +// API error codes. +const ( + // Factory errors + IdInUse ErrorCode = iota + InvalidIdFormat + + // Container errors + ContainerNotExists + ContainerPaused + ContainerNotStopped + ContainerNotRunning + ContainerNotPaused + + // Process errors + NoProcessOps + + // Common errors + ConfigInvalid + ConsoleExists + SystemError +) + +func (c ErrorCode) String() string { + switch c { + case IdInUse: + return "Id already in use" + case InvalidIdFormat: + return "Invalid format" + case ContainerPaused: + return "Container paused" + case ConfigInvalid: + return "Invalid configuration" + case SystemError: + return "System error" + case ContainerNotExists: + return "Container does not exist" + case ContainerNotStopped: + return "Container is not stopped" + case ContainerNotRunning: + return "Container is not running" + case ConsoleExists: + return "Console exists for process" + case ContainerNotPaused: + return "Container is not paused" + case NoProcessOps: + return "No process operations" + default: + return "Unknown error" + } +} + +// Error is the API error type. +type Error interface { + error + + // Returns an error if it failed to write the detail of the Error to w. + // The detail of the Error may include the error message and a + // representation of the stack trace. + Detail(w io.Writer) error + + // Returns the error code for this error. + Code() ErrorCode +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/factory.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/factory.go new file mode 100644 index 000000000000..0986cd77e3fe --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/factory.go @@ -0,0 +1,44 @@ +package libcontainer + +import ( + "github.com/opencontainers/runc/libcontainer/configs" +) + +type Factory interface { + // Creates a new container with the given id and starts the initial process inside it. + // id must be a string containing only letters, digits and underscores and must contain + // between 1 and 1024 characters, inclusive. + // + // The id must not already be in use by an existing container. Containers created using + // a factory with the same path (and filesystem) must have distinct ids. + // + // Returns the new container with a running process. + // + // errors: + // IdInUse - id is already in use by a container + // InvalidIdFormat - id has incorrect format + // ConfigInvalid - config is invalid + // Systemerror - System error + // + // On error, any partially created container parts are cleaned up (the operation is atomic). + Create(id string, config *configs.Config) (Container, error) + + // Load takes an ID for an existing container and returns the container information + // from the state. This presents a read only view of the container. + // + // errors: + // Path does not exist + // System error + Load(id string) (Container, error) + + // StartInitialization is an internal API to libcontainer used during the reexec of the + // container. + // + // Errors: + // Pipe connection error + // System error + StartInitialization() error + + // Type returns info string about factory type (e.g. lxc, libcontainer...) + Type() string +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/factory_linux.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/factory_linux.go new file mode 100644 index 000000000000..5cd374162b93 --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/factory_linux.go @@ -0,0 +1,443 @@ +// +build linux + +package libcontainer + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + "regexp" + "runtime/debug" + "strconv" + + securejoin "github.com/cyphar/filepath-securejoin" + "github.com/moby/sys/mountinfo" + "github.com/opencontainers/runc/libcontainer/cgroups" + "github.com/opencontainers/runc/libcontainer/cgroups/fs" + "github.com/opencontainers/runc/libcontainer/cgroups/fs2" + "github.com/opencontainers/runc/libcontainer/cgroups/systemd" + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/configs/validate" + "github.com/opencontainers/runc/libcontainer/intelrdt" + "github.com/opencontainers/runc/libcontainer/utils" + "github.com/pkg/errors" + + "golang.org/x/sys/unix" +) + +const ( + stateFilename = "state.json" + execFifoFilename = "exec.fifo" +) + +var idRegex = regexp.MustCompile(`^[\w+-\.]+$`) + +// InitArgs returns an options func to configure a LinuxFactory with the +// provided init binary path and arguments. +func InitArgs(args ...string) func(*LinuxFactory) error { + return func(l *LinuxFactory) (err error) { + if len(args) > 0 { + // Resolve relative paths to ensure that its available + // after directory changes. + if args[0], err = filepath.Abs(args[0]); err != nil { + return newGenericError(err, ConfigInvalid) + } + } + + l.InitArgs = args + return nil + } +} + +func getUnifiedPath(paths map[string]string) string { + path := "" + for k, v := range paths { + if path == "" { + path = v + } else if v != path { + panic(errors.Errorf("expected %q path to be unified path %q, got %q", k, path, v)) + } + } + // can be empty + if path != "" { + if filepath.Clean(path) != path || !filepath.IsAbs(path) { + panic(errors.Errorf("invalid dir path %q", path)) + } + } + + return path +} + +func systemdCgroupV2(l *LinuxFactory, rootless bool) error { + l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager { + return systemd.NewUnifiedManager(config, getUnifiedPath(paths), rootless) + } + return nil +} + +// SystemdCgroups is an options func to configure a LinuxFactory to return +// containers that use systemd to create and manage cgroups. +func SystemdCgroups(l *LinuxFactory) error { + if !systemd.IsRunningSystemd() { + return fmt.Errorf("systemd not running on this host, can't use systemd as cgroups manager") + } + + if cgroups.IsCgroup2UnifiedMode() { + return systemdCgroupV2(l, false) + } + + l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager { + return systemd.NewLegacyManager(config, paths) + } + + return nil +} + +// RootlessSystemdCgroups is rootless version of SystemdCgroups. +func RootlessSystemdCgroups(l *LinuxFactory) error { + if !systemd.IsRunningSystemd() { + return fmt.Errorf("systemd not running on this host, can't use systemd as cgroups manager") + } + + if !cgroups.IsCgroup2UnifiedMode() { + return fmt.Errorf("cgroup v2 not enabled on this host, can't use systemd (rootless) as cgroups manager") + } + return systemdCgroupV2(l, true) +} + +func cgroupfs2(l *LinuxFactory, rootless bool) error { + l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager { + m, err := fs2.NewManager(config, getUnifiedPath(paths), rootless) + if err != nil { + panic(err) + } + return m + } + return nil +} + +func cgroupfs(l *LinuxFactory, rootless bool) error { + if cgroups.IsCgroup2UnifiedMode() { + return cgroupfs2(l, rootless) + } + l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager { + return fs.NewManager(config, paths, rootless) + } + return nil +} + +// Cgroupfs is an options func to configure a LinuxFactory to return containers +// that use the native cgroups filesystem implementation to create and manage +// cgroups. +func Cgroupfs(l *LinuxFactory) error { + return cgroupfs(l, false) +} + +// RootlessCgroupfs is an options func to configure a LinuxFactory to return +// containers that use the native cgroups filesystem implementation to create +// and manage cgroups. The difference between RootlessCgroupfs and Cgroupfs is +// that RootlessCgroupfs can transparently handle permission errors that occur +// during rootless container (including euid=0 in userns) setup (while still allowing cgroup usage if +// they've been set up properly). +func RootlessCgroupfs(l *LinuxFactory) error { + return cgroupfs(l, true) +} + +// IntelRdtfs is an options func to configure a LinuxFactory to return +// containers that use the Intel RDT "resource control" filesystem to +// create and manage Intel RDT resources (e.g., L3 cache, memory bandwidth). +func IntelRdtFs(l *LinuxFactory) error { + if !intelrdt.IsCATEnabled() && !intelrdt.IsMBAEnabled() { + l.NewIntelRdtManager = nil + } else { + l.NewIntelRdtManager = func(config *configs.Config, id string, path string) intelrdt.Manager { + return intelrdt.NewManager(config, id, path) + } + } + return nil +} + +// TmpfsRoot is an option func to mount LinuxFactory.Root to tmpfs. +func TmpfsRoot(l *LinuxFactory) error { + mounted, err := mountinfo.Mounted(l.Root) + if err != nil { + return err + } + if !mounted { + if err := unix.Mount("tmpfs", l.Root, "tmpfs", 0, ""); err != nil { + return err + } + } + return nil +} + +// CriuPath returns an option func to configure a LinuxFactory with the +// provided criupath +func CriuPath(criupath string) func(*LinuxFactory) error { + return func(l *LinuxFactory) error { + l.CriuPath = criupath + return nil + } +} + +// New returns a linux based container factory based in the root directory and +// configures the factory with the provided option funcs. +func New(root string, options ...func(*LinuxFactory) error) (Factory, error) { + if root != "" { + if err := os.MkdirAll(root, 0700); err != nil { + return nil, newGenericError(err, SystemError) + } + } + l := &LinuxFactory{ + Root: root, + InitPath: "/proc/self/exe", + InitArgs: []string{os.Args[0], "init"}, + Validator: validate.New(), + CriuPath: "criu", + } + Cgroupfs(l) + for _, opt := range options { + if opt == nil { + continue + } + if err := opt(l); err != nil { + return nil, err + } + } + return l, nil +} + +// LinuxFactory implements the default factory interface for linux based systems. +type LinuxFactory struct { + // Root directory for the factory to store state. + Root string + + // InitPath is the path for calling the init responsibilities for spawning + // a container. + InitPath string + + // InitArgs are arguments for calling the init responsibilities for spawning + // a container. + InitArgs []string + + // CriuPath is the path to the criu binary used for checkpoint and restore of + // containers. + CriuPath string + + // New{u,g}uidmapPath is the path to the binaries used for mapping with + // rootless containers. + NewuidmapPath string + NewgidmapPath string + + // Validator provides validation to container configurations. + Validator validate.Validator + + // NewCgroupsManager returns an initialized cgroups manager for a single container. + NewCgroupsManager func(config *configs.Cgroup, paths map[string]string) cgroups.Manager + + // NewIntelRdtManager returns an initialized Intel RDT manager for a single container. + NewIntelRdtManager func(config *configs.Config, id string, path string) intelrdt.Manager +} + +func (l *LinuxFactory) Create(id string, config *configs.Config) (Container, error) { + if l.Root == "" { + return nil, newGenericError(fmt.Errorf("invalid root"), ConfigInvalid) + } + if err := l.validateID(id); err != nil { + return nil, err + } + if err := l.Validator.Validate(config); err != nil { + return nil, newGenericError(err, ConfigInvalid) + } + containerRoot, err := securejoin.SecureJoin(l.Root, id) + if err != nil { + return nil, err + } + if _, err := os.Stat(containerRoot); err == nil { + return nil, newGenericError(fmt.Errorf("container with id exists: %v", id), IdInUse) + } else if !os.IsNotExist(err) { + return nil, newGenericError(err, SystemError) + } + if err := os.MkdirAll(containerRoot, 0711); err != nil { + return nil, newGenericError(err, SystemError) + } + if err := os.Chown(containerRoot, unix.Geteuid(), unix.Getegid()); err != nil { + return nil, newGenericError(err, SystemError) + } + c := &linuxContainer{ + id: id, + root: containerRoot, + config: config, + initPath: l.InitPath, + initArgs: l.InitArgs, + criuPath: l.CriuPath, + newuidmapPath: l.NewuidmapPath, + newgidmapPath: l.NewgidmapPath, + cgroupManager: l.NewCgroupsManager(config.Cgroups, nil), + } + if l.NewIntelRdtManager != nil { + c.intelRdtManager = l.NewIntelRdtManager(config, id, "") + } + c.state = &stoppedState{c: c} + return c, nil +} + +func (l *LinuxFactory) Load(id string) (Container, error) { + if l.Root == "" { + return nil, newGenericError(fmt.Errorf("invalid root"), ConfigInvalid) + } + //when load, we need to check id is valid or not. + if err := l.validateID(id); err != nil { + return nil, err + } + containerRoot, err := securejoin.SecureJoin(l.Root, id) + if err != nil { + return nil, err + } + state, err := l.loadState(containerRoot, id) + if err != nil { + return nil, err + } + r := &nonChildProcess{ + processPid: state.InitProcessPid, + processStartTime: state.InitProcessStartTime, + fds: state.ExternalDescriptors, + } + c := &linuxContainer{ + initProcess: r, + initProcessStartTime: state.InitProcessStartTime, + id: id, + config: &state.Config, + initPath: l.InitPath, + initArgs: l.InitArgs, + criuPath: l.CriuPath, + newuidmapPath: l.NewuidmapPath, + newgidmapPath: l.NewgidmapPath, + cgroupManager: l.NewCgroupsManager(state.Config.Cgroups, state.CgroupPaths), + root: containerRoot, + created: state.Created, + } + if l.NewIntelRdtManager != nil { + c.intelRdtManager = l.NewIntelRdtManager(&state.Config, id, state.IntelRdtPath) + } + c.state = &loadedState{c: c} + if err := c.refreshState(); err != nil { + return nil, err + } + return c, nil +} + +func (l *LinuxFactory) Type() string { + return "libcontainer" +} + +// StartInitialization loads a container by opening the pipe fd from the parent to read the configuration and state +// This is a low level implementation detail of the reexec and should not be consumed externally +func (l *LinuxFactory) StartInitialization() (err error) { + // Get the INITPIPE. + envInitPipe := os.Getenv("_LIBCONTAINER_INITPIPE") + pipefd, err := strconv.Atoi(envInitPipe) + if err != nil { + return fmt.Errorf("unable to convert _LIBCONTAINER_INITPIPE=%s to int: %s", envInitPipe, err) + } + pipe := os.NewFile(uintptr(pipefd), "pipe") + defer pipe.Close() + + // Only init processes have FIFOFD. + fifofd := -1 + envInitType := os.Getenv("_LIBCONTAINER_INITTYPE") + it := initType(envInitType) + if it == initStandard { + envFifoFd := os.Getenv("_LIBCONTAINER_FIFOFD") + if fifofd, err = strconv.Atoi(envFifoFd); err != nil { + return fmt.Errorf("unable to convert _LIBCONTAINER_FIFOFD=%s to int: %s", envFifoFd, err) + } + } + + var consoleSocket *os.File + if envConsole := os.Getenv("_LIBCONTAINER_CONSOLE"); envConsole != "" { + console, err := strconv.Atoi(envConsole) + if err != nil { + return fmt.Errorf("unable to convert _LIBCONTAINER_CONSOLE=%s to int: %s", envConsole, err) + } + consoleSocket = os.NewFile(uintptr(console), "console-socket") + defer consoleSocket.Close() + } + + // clear the current process's environment to clean any libcontainer + // specific env vars. + os.Clearenv() + + defer func() { + // We have an error during the initialization of the container's init, + // send it back to the parent process in the form of an initError. + if werr := utils.WriteJSON(pipe, syncT{procError}); werr != nil { + fmt.Fprintln(os.Stderr, err) + return + } + if werr := utils.WriteJSON(pipe, newSystemError(err)); werr != nil { + fmt.Fprintln(os.Stderr, err) + return + } + }() + defer func() { + if e := recover(); e != nil { + err = fmt.Errorf("panic from initialization: %v, %v", e, string(debug.Stack())) + } + }() + + i, err := newContainerInit(it, pipe, consoleSocket, fifofd) + if err != nil { + return err + } + + // If Init succeeds, syscall.Exec will not return, hence none of the defers will be called. + return i.Init() +} + +func (l *LinuxFactory) loadState(root, id string) (*State, error) { + stateFilePath, err := securejoin.SecureJoin(root, stateFilename) + if err != nil { + return nil, err + } + f, err := os.Open(stateFilePath) + if err != nil { + if os.IsNotExist(err) { + return nil, newGenericError(fmt.Errorf("container %q does not exist", id), ContainerNotExists) + } + return nil, newGenericError(err, SystemError) + } + defer f.Close() + var state *State + if err := json.NewDecoder(f).Decode(&state); err != nil { + return nil, newGenericError(err, SystemError) + } + return state, nil +} + +func (l *LinuxFactory) validateID(id string) error { + if !idRegex.MatchString(id) || string(os.PathSeparator)+id != utils.CleanPath(string(os.PathSeparator)+id) { + return newGenericError(fmt.Errorf("invalid id format: %v", id), InvalidIdFormat) + } + + return nil +} + +// NewuidmapPath returns an option func to configure a LinuxFactory with the +// provided .. +func NewuidmapPath(newuidmapPath string) func(*LinuxFactory) error { + return func(l *LinuxFactory) error { + l.NewuidmapPath = newuidmapPath + return nil + } +} + +// NewgidmapPath returns an option func to configure a LinuxFactory with the +// provided .. +func NewgidmapPath(newgidmapPath string) func(*LinuxFactory) error { + return func(l *LinuxFactory) error { + l.NewgidmapPath = newgidmapPath + return nil + } +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/generic_error.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/generic_error.go new file mode 100644 index 000000000000..d185ebd89898 --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/generic_error.go @@ -0,0 +1,92 @@ +package libcontainer + +import ( + "fmt" + "io" + "text/template" + "time" + + "github.com/opencontainers/runc/libcontainer/stacktrace" +) + +var errorTemplate = template.Must(template.New("error").Parse(`Timestamp: {{.Timestamp}} +Code: {{.ECode}} +{{if .Message }} +Message: {{.Message}} +{{end}} +Frames:{{range $i, $frame := .Stack.Frames}} +--- +{{$i}}: {{$frame.Function}} +Package: {{$frame.Package}} +File: {{$frame.File}}@{{$frame.Line}}{{end}} +`)) + +func newGenericError(err error, c ErrorCode) Error { + if le, ok := err.(Error); ok { + return le + } + gerr := &genericError{ + Timestamp: time.Now(), + Err: err, + ECode: c, + Stack: stacktrace.Capture(1), + } + if err != nil { + gerr.Message = err.Error() + } + return gerr +} + +func newSystemError(err error) Error { + return createSystemError(err, "") +} + +func newSystemErrorWithCausef(err error, cause string, v ...interface{}) Error { + return createSystemError(err, fmt.Sprintf(cause, v...)) +} + +func newSystemErrorWithCause(err error, cause string) Error { + return createSystemError(err, cause) +} + +// createSystemError creates the specified error with the correct number of +// stack frames skipped. This is only to be called by the other functions for +// formatting the error. +func createSystemError(err error, cause string) Error { + gerr := &genericError{ + Timestamp: time.Now(), + Err: err, + ECode: SystemError, + Cause: cause, + Stack: stacktrace.Capture(2), + } + if err != nil { + gerr.Message = err.Error() + } + return gerr +} + +type genericError struct { + Timestamp time.Time + ECode ErrorCode + Err error `json:"-"` + Cause string + Message string + Stack stacktrace.Stacktrace +} + +func (e *genericError) Error() string { + if e.Cause == "" { + return e.Message + } + frame := e.Stack.Frames[0] + return fmt.Sprintf("%s:%d: %s caused: %s", frame.File, frame.Line, e.Cause, e.Message) +} + +func (e *genericError) Code() ErrorCode { + return e.ECode +} + +func (e *genericError) Detail(w io.Writer) error { + return errorTemplate.Execute(w, e) +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/init_linux.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/init_linux.go new file mode 100644 index 000000000000..c57af0eebb8b --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/init_linux.go @@ -0,0 +1,544 @@ +// +build linux + +package libcontainer + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net" + "os" + "strings" + "unsafe" + + "github.com/containerd/console" + "github.com/opencontainers/runc/libcontainer/capabilities" + "github.com/opencontainers/runc/libcontainer/cgroups" + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/system" + "github.com/opencontainers/runc/libcontainer/user" + "github.com/opencontainers/runc/libcontainer/utils" + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "github.com/vishvananda/netlink" + "golang.org/x/sys/unix" +) + +type initType string + +const ( + initSetns initType = "setns" + initStandard initType = "standard" +) + +type pid struct { + Pid int `json:"pid"` + PidFirstChild int `json:"pid_first"` +} + +// network is an internal struct used to setup container networks. +type network struct { + configs.Network + + // TempVethPeerName is a unique temporary veth peer name that was placed into + // the container's namespace. + TempVethPeerName string `json:"temp_veth_peer_name"` +} + +// initConfig is used for transferring parameters from Exec() to Init() +type initConfig struct { + Args []string `json:"args"` + Env []string `json:"env"` + Cwd string `json:"cwd"` + Capabilities *configs.Capabilities `json:"capabilities"` + ProcessLabel string `json:"process_label"` + AppArmorProfile string `json:"apparmor_profile"` + NoNewPrivileges bool `json:"no_new_privileges"` + User string `json:"user"` + AdditionalGroups []string `json:"additional_groups"` + Config *configs.Config `json:"config"` + Networks []*network `json:"network"` + PassedFilesCount int `json:"passed_files_count"` + ContainerId string `json:"containerid"` + Rlimits []configs.Rlimit `json:"rlimits"` + CreateConsole bool `json:"create_console"` + ConsoleWidth uint16 `json:"console_width"` + ConsoleHeight uint16 `json:"console_height"` + RootlessEUID bool `json:"rootless_euid,omitempty"` + RootlessCgroups bool `json:"rootless_cgroups,omitempty"` + SpecState *specs.State `json:"spec_state,omitempty"` +} + +type initer interface { + Init() error +} + +func newContainerInit(t initType, pipe *os.File, consoleSocket *os.File, fifoFd int) (initer, error) { + var config *initConfig + if err := json.NewDecoder(pipe).Decode(&config); err != nil { + return nil, err + } + if err := populateProcessEnvironment(config.Env); err != nil { + return nil, err + } + switch t { + case initSetns: + return &linuxSetnsInit{ + pipe: pipe, + consoleSocket: consoleSocket, + config: config, + }, nil + case initStandard: + return &linuxStandardInit{ + pipe: pipe, + consoleSocket: consoleSocket, + parentPid: unix.Getppid(), + config: config, + fifoFd: fifoFd, + }, nil + } + return nil, fmt.Errorf("unknown init type %q", t) +} + +// populateProcessEnvironment loads the provided environment variables into the +// current processes's environment. +func populateProcessEnvironment(env []string) error { + for _, pair := range env { + p := strings.SplitN(pair, "=", 2) + if len(p) < 2 { + return fmt.Errorf("invalid environment '%v'", pair) + } + if err := os.Setenv(p[0], p[1]); err != nil { + return err + } + } + return nil +} + +// finalizeNamespace drops the caps, sets the correct user +// and working dir, and closes any leaked file descriptors +// before executing the command inside the namespace +func finalizeNamespace(config *initConfig) error { + // Ensure that all unwanted fds we may have accidentally + // inherited are marked close-on-exec so they stay out of the + // container + if err := utils.CloseExecFrom(config.PassedFilesCount + 3); err != nil { + return errors.Wrap(err, "close exec fds") + } + + caps := &configs.Capabilities{} + if config.Capabilities != nil { + caps = config.Capabilities + } else if config.Config.Capabilities != nil { + caps = config.Config.Capabilities + } + w, err := capabilities.New(caps) + if err != nil { + return err + } + // drop capabilities in bounding set before changing user + if err := w.ApplyBoundingSet(); err != nil { + return errors.Wrap(err, "apply bounding set") + } + // preserve existing capabilities while we change users + if err := system.SetKeepCaps(); err != nil { + return errors.Wrap(err, "set keep caps") + } + if err := setupUser(config); err != nil { + return errors.Wrap(err, "setup user") + } + // Change working directory AFTER the user has been set up. + // Otherwise, if the cwd is also a volume that's been chowned to the container user (and not the user running runc), + // this command will EPERM. + if config.Cwd != "" { + if err := unix.Chdir(config.Cwd); err != nil { + return fmt.Errorf("chdir to cwd (%q) set in config.json failed: %v", config.Cwd, err) + } + } + if err := system.ClearKeepCaps(); err != nil { + return errors.Wrap(err, "clear keep caps") + } + if err := w.ApplyCaps(); err != nil { + return errors.Wrap(err, "apply caps") + } + return nil +} + +// setupConsole sets up the console from inside the container, and sends the +// master pty fd to the config.Pipe (using cmsg). This is done to ensure that +// consoles are scoped to a container properly (see runc#814 and the many +// issues related to that). This has to be run *after* we've pivoted to the new +// rootfs (and the users' configuration is entirely set up). +func setupConsole(socket *os.File, config *initConfig, mount bool) error { + defer socket.Close() + // At this point, /dev/ptmx points to something that we would expect. We + // used to change the owner of the slave path, but since the /dev/pts mount + // can have gid=X set (at the users' option). So touching the owner of the + // slave PTY is not necessary, as the kernel will handle that for us. Note + // however, that setupUser (specifically fixStdioPermissions) *will* change + // the UID owner of the console to be the user the process will run as (so + // they can actually control their console). + + pty, slavePath, err := console.NewPty() + if err != nil { + return err + } + + // After we return from here, we don't need the console anymore. + defer pty.Close() + + if config.ConsoleHeight != 0 && config.ConsoleWidth != 0 { + err = pty.Resize(console.WinSize{ + Height: config.ConsoleHeight, + Width: config.ConsoleWidth, + }) + + if err != nil { + return err + } + } + + // Mount the console inside our rootfs. + if mount { + if err := mountConsole(slavePath); err != nil { + return err + } + } + // While we can access console.master, using the API is a good idea. + if err := utils.SendFd(socket, pty.Name(), pty.Fd()); err != nil { + return err + } + // Now, dup over all the things. + return dupStdio(slavePath) +} + +// syncParentReady sends to the given pipe a JSON payload which indicates that +// the init is ready to Exec the child process. It then waits for the parent to +// indicate that it is cleared to Exec. +func syncParentReady(pipe io.ReadWriter) error { + // Tell parent. + if err := writeSync(pipe, procReady); err != nil { + return err + } + + // Wait for parent to give the all-clear. + return readSync(pipe, procRun) +} + +// syncParentHooks sends to the given pipe a JSON payload which indicates that +// the parent should execute pre-start hooks. It then waits for the parent to +// indicate that it is cleared to resume. +func syncParentHooks(pipe io.ReadWriter) error { + // Tell parent. + if err := writeSync(pipe, procHooks); err != nil { + return err + } + + // Wait for parent to give the all-clear. + return readSync(pipe, procResume) +} + +// setupUser changes the groups, gid, and uid for the user inside the container +func setupUser(config *initConfig) error { + // Set up defaults. + defaultExecUser := user.ExecUser{ + Uid: 0, + Gid: 0, + Home: "/", + } + + passwdPath, err := user.GetPasswdPath() + if err != nil { + return err + } + + groupPath, err := user.GetGroupPath() + if err != nil { + return err + } + + execUser, err := user.GetExecUserPath(config.User, &defaultExecUser, passwdPath, groupPath) + if err != nil { + return err + } + + var addGroups []int + if len(config.AdditionalGroups) > 0 { + addGroups, err = user.GetAdditionalGroupsPath(config.AdditionalGroups, groupPath) + if err != nil { + return err + } + } + + // Rather than just erroring out later in setuid(2) and setgid(2), check + // that the user is mapped here. + if _, err := config.Config.HostUID(execUser.Uid); err != nil { + return errors.New("cannot set uid to unmapped user in user namespace") + } + if _, err := config.Config.HostGID(execUser.Gid); err != nil { + return errors.New("cannot set gid to unmapped user in user namespace") + } + + if config.RootlessEUID { + // We cannot set any additional groups in a rootless container and thus + // we bail if the user asked us to do so. TODO: We currently can't do + // this check earlier, but if libcontainer.Process.User was typesafe + // this might work. + if len(addGroups) > 0 { + return errors.New("cannot set any additional groups in a rootless container") + } + } + + // Before we change to the container's user make sure that the processes + // STDIO is correctly owned by the user that we are switching to. + if err := fixStdioPermissions(config, execUser); err != nil { + return err + } + + setgroups, err := ioutil.ReadFile("/proc/self/setgroups") + if err != nil && !os.IsNotExist(err) { + return err + } + + // This isn't allowed in an unprivileged user namespace since Linux 3.19. + // There's nothing we can do about /etc/group entries, so we silently + // ignore setting groups here (since the user didn't explicitly ask us to + // set the group). + allowSupGroups := !config.RootlessEUID && string(bytes.TrimSpace(setgroups)) != "deny" + + if allowSupGroups { + suppGroups := append(execUser.Sgids, addGroups...) + if err := unix.Setgroups(suppGroups); err != nil { + return err + } + } + + if err := system.Setgid(execUser.Gid); err != nil { + return err + } + if err := system.Setuid(execUser.Uid); err != nil { + return err + } + + // if we didn't get HOME already, set it based on the user's HOME + if envHome := os.Getenv("HOME"); envHome == "" { + if err := os.Setenv("HOME", execUser.Home); err != nil { + return err + } + } + return nil +} + +// fixStdioPermissions fixes the permissions of PID 1's STDIO within the container to the specified user. +// The ownership needs to match because it is created outside of the container and needs to be +// localized. +func fixStdioPermissions(config *initConfig, u *user.ExecUser) error { + var null unix.Stat_t + if err := unix.Stat("/dev/null", &null); err != nil { + return err + } + for _, fd := range []uintptr{ + os.Stdin.Fd(), + os.Stderr.Fd(), + os.Stdout.Fd(), + } { + var s unix.Stat_t + if err := unix.Fstat(int(fd), &s); err != nil { + return err + } + + // Skip chown of /dev/null if it was used as one of the STDIO fds. + if s.Rdev == null.Rdev { + continue + } + + // We only change the uid owner (as it is possible for the mount to + // prefer a different gid, and there's no reason for us to change it). + // The reason why we don't just leave the default uid=X mount setup is + // that users expect to be able to actually use their console. Without + // this code, you couldn't effectively run as a non-root user inside a + // container and also have a console set up. + if err := unix.Fchown(int(fd), u.Uid, int(s.Gid)); err != nil { + // If we've hit an EINVAL then s.Gid isn't mapped in the user + // namespace. If we've hit an EPERM then the inode's current owner + // is not mapped in our user namespace (in particular, + // privileged_wrt_inode_uidgid() has failed). In either case, we + // are in a configuration where it's better for us to just not + // touch the stdio rather than bail at this point. + if err == unix.EINVAL || err == unix.EPERM { + continue + } + return err + } + } + return nil +} + +// setupNetwork sets up and initializes any network interface inside the container. +func setupNetwork(config *initConfig) error { + for _, config := range config.Networks { + strategy, err := getStrategy(config.Type) + if err != nil { + return err + } + if err := strategy.initialize(config); err != nil { + return err + } + } + return nil +} + +func setupRoute(config *configs.Config) error { + for _, config := range config.Routes { + _, dst, err := net.ParseCIDR(config.Destination) + if err != nil { + return err + } + src := net.ParseIP(config.Source) + if src == nil { + return fmt.Errorf("Invalid source for route: %s", config.Source) + } + gw := net.ParseIP(config.Gateway) + if gw == nil { + return fmt.Errorf("Invalid gateway for route: %s", config.Gateway) + } + l, err := netlink.LinkByName(config.InterfaceName) + if err != nil { + return err + } + route := &netlink.Route{ + Scope: netlink.SCOPE_UNIVERSE, + Dst: dst, + Src: src, + Gw: gw, + LinkIndex: l.Attrs().Index, + } + if err := netlink.RouteAdd(route); err != nil { + return err + } + } + return nil +} + +func setupRlimits(limits []configs.Rlimit, pid int) error { + for _, rlimit := range limits { + if err := system.Prlimit(pid, rlimit.Type, unix.Rlimit{Max: rlimit.Hard, Cur: rlimit.Soft}); err != nil { + return fmt.Errorf("error setting rlimit type %v: %v", rlimit.Type, err) + } + } + return nil +} + +const _P_PID = 1 + +//nolint:structcheck,unused +type siginfo struct { + si_signo int32 + si_errno int32 + si_code int32 + // below here is a union; si_pid is the only field we use + si_pid int32 + // Pad to 128 bytes as detailed in blockUntilWaitable + pad [96]byte +} + +// isWaitable returns true if the process has exited false otherwise. +// Its based off blockUntilWaitable in src/os/wait_waitid.go +func isWaitable(pid int) (bool, error) { + si := &siginfo{} + _, _, e := unix.Syscall6(unix.SYS_WAITID, _P_PID, uintptr(pid), uintptr(unsafe.Pointer(si)), unix.WEXITED|unix.WNOWAIT|unix.WNOHANG, 0, 0) + if e != 0 { + return false, os.NewSyscallError("waitid", e) + } + + return si.si_pid != 0, nil +} + +// isNoChildren returns true if err represents a unix.ECHILD (formerly syscall.ECHILD) false otherwise +func isNoChildren(err error) bool { + switch err := err.(type) { + case unix.Errno: + if err == unix.ECHILD { + return true + } + case *os.SyscallError: + if err.Err == unix.ECHILD { + return true + } + } + return false +} + +// signalAllProcesses freezes then iterates over all the processes inside the +// manager's cgroups sending the signal s to them. +// If s is SIGKILL then it will wait for each process to exit. +// For all other signals it will check if the process is ready to report its +// exit status and only if it is will a wait be performed. +func signalAllProcesses(m cgroups.Manager, s os.Signal) error { + var procs []*os.Process + if err := m.Freeze(configs.Frozen); err != nil { + logrus.Warn(err) + } + pids, err := m.GetAllPids() + if err != nil { + if err := m.Freeze(configs.Thawed); err != nil { + logrus.Warn(err) + } + return err + } + for _, pid := range pids { + p, err := os.FindProcess(pid) + if err != nil { + logrus.Warn(err) + continue + } + procs = append(procs, p) + if err := p.Signal(s); err != nil { + logrus.Warn(err) + } + } + if err := m.Freeze(configs.Thawed); err != nil { + logrus.Warn(err) + } + + subreaper, err := system.GetSubreaper() + if err != nil { + // The error here means that PR_GET_CHILD_SUBREAPER is not + // supported because this code might run on a kernel older + // than 3.4. We don't want to throw an error in that case, + // and we simplify things, considering there is no subreaper + // set. + subreaper = 0 + } + + for _, p := range procs { + if s != unix.SIGKILL { + if ok, err := isWaitable(p.Pid); err != nil { + if !isNoChildren(err) { + logrus.Warn("signalAllProcesses: ", p.Pid, err) + } + continue + } else if !ok { + // Not ready to report so don't wait + continue + } + } + + // In case a subreaper has been setup, this code must not + // wait for the process. Otherwise, we cannot be sure the + // current process will be reaped by the subreaper, while + // the subreaper might be waiting for this process in order + // to retrieve its exit code. + if subreaper == 0 { + if _, err := p.Wait(); err != nil { + if !isNoChildren(err) { + logrus.Warn("wait: ", err) + } + } + } + } + return nil +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/cmt.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/cmt.go new file mode 100644 index 000000000000..ed950973f080 --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/cmt.go @@ -0,0 +1,25 @@ +package intelrdt + +var ( + cmtEnabled bool +) + +// Check if Intel RDT/CMT is enabled. +func IsCMTEnabled() bool { + featuresInit() + return cmtEnabled +} + +func getCMTNumaNodeStats(numaPath string) (*CMTNumaNodeStats, error) { + stats := &CMTNumaNodeStats{} + + if enabledMonFeatures.llcOccupancy { + llcOccupancy, err := getIntelRdtParamUint(numaPath, "llc_occupancy") + if err != nil { + return nil, err + } + stats.LLCOccupancy = llcOccupancy + } + + return stats, nil +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt.go new file mode 100644 index 000000000000..3fa11b8002d3 --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt.go @@ -0,0 +1,816 @@ +// +build linux + +package intelrdt + +import ( + "bufio" + "bytes" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "strconv" + "strings" + "sync" + + "github.com/moby/sys/mountinfo" + "github.com/opencontainers/runc/libcontainer/configs" +) + +/* + * About Intel RDT features: + * Intel platforms with new Xeon CPU support Resource Director Technology (RDT). + * Cache Allocation Technology (CAT) and Memory Bandwidth Allocation (MBA) are + * two sub-features of RDT. + * + * Cache Allocation Technology (CAT) provides a way for the software to restrict + * cache allocation to a defined 'subset' of L3 cache which may be overlapping + * with other 'subsets'. The different subsets are identified by class of + * service (CLOS) and each CLOS has a capacity bitmask (CBM). + * + * Memory Bandwidth Allocation (MBA) provides indirect and approximate throttle + * over memory bandwidth for the software. A user controls the resource by + * indicating the percentage of maximum memory bandwidth or memory bandwidth + * limit in MBps unit if MBA Software Controller is enabled. + * + * More details about Intel RDT CAT and MBA can be found in the section 17.18 + * of Intel Software Developer Manual: + * https://software.intel.com/en-us/articles/intel-sdm + * + * About Intel RDT kernel interface: + * In Linux 4.10 kernel or newer, the interface is defined and exposed via + * "resource control" filesystem, which is a "cgroup-like" interface. + * + * Comparing with cgroups, it has similar process management lifecycle and + * interfaces in a container. But unlike cgroups' hierarchy, it has single level + * filesystem layout. + * + * CAT and MBA features are introduced in Linux 4.10 and 4.12 kernel via + * "resource control" filesystem. + * + * Intel RDT "resource control" filesystem hierarchy: + * mount -t resctrl resctrl /sys/fs/resctrl + * tree /sys/fs/resctrl + * /sys/fs/resctrl/ + * |-- info + * | |-- L3 + * | | |-- cbm_mask + * | | |-- min_cbm_bits + * | | |-- num_closids + * | |-- L3_MON + * | | |-- max_threshold_occupancy + * | | |-- mon_features + * | | |-- num_rmids + * | |-- MB + * | |-- bandwidth_gran + * | |-- delay_linear + * | |-- min_bandwidth + * | |-- num_closids + * |-- ... + * |-- schemata + * |-- tasks + * |-- + * |-- ... + * |-- schemata + * |-- tasks + * + * For runc, we can make use of `tasks` and `schemata` configuration for L3 + * cache and memory bandwidth resources constraints. + * + * The file `tasks` has a list of tasks that belongs to this group (e.g., + * " group). Tasks can be added to a group by writing the task ID + * to the "tasks" file (which will automatically remove them from the previous + * group to which they belonged). New tasks created by fork(2) and clone(2) are + * added to the same group as their parent. + * + * The file `schemata` has a list of all the resources available to this group. + * Each resource (L3 cache, memory bandwidth) has its own line and format. + * + * L3 cache schema: + * It has allocation bitmasks/values for L3 cache on each socket, which + * contains L3 cache id and capacity bitmask (CBM). + * Format: "L3:=;=;..." + * For example, on a two-socket machine, the schema line could be "L3:0=ff;1=c0" + * which means L3 cache id 0's CBM is 0xff, and L3 cache id 1's CBM is 0xc0. + * + * The valid L3 cache CBM is a *contiguous bits set* and number of bits that can + * be set is less than the max bit. The max bits in the CBM is varied among + * supported Intel CPU models. Kernel will check if it is valid when writing. + * e.g., default value 0xfffff in root indicates the max bits of CBM is 20 + * bits, which mapping to entire L3 cache capacity. Some valid CBM values to + * set in a group: 0xf, 0xf0, 0x3ff, 0x1f00 and etc. + * + * Memory bandwidth schema: + * It has allocation values for memory bandwidth on each socket, which contains + * L3 cache id and memory bandwidth. + * Format: "MB:=bandwidth0;=bandwidth1;..." + * For example, on a two-socket machine, the schema line could be "MB:0=20;1=70" + * + * The minimum bandwidth percentage value for each CPU model is predefined and + * can be looked up through "info/MB/min_bandwidth". The bandwidth granularity + * that is allocated is also dependent on the CPU model and can be looked up at + * "info/MB/bandwidth_gran". The available bandwidth control steps are: + * min_bw + N * bw_gran. Intermediate values are rounded to the next control + * step available on the hardware. + * + * If MBA Software Controller is enabled through mount option "-o mba_MBps": + * mount -t resctrl resctrl -o mba_MBps /sys/fs/resctrl + * We could specify memory bandwidth in "MBps" (Mega Bytes per second) unit + * instead of "percentages". The kernel underneath would use a software feedback + * mechanism or a "Software Controller" which reads the actual bandwidth using + * MBM counters and adjust the memory bandwidth percentages to ensure: + * "actual memory bandwidth < user specified memory bandwidth". + * + * For example, on a two-socket machine, the schema line could be + * "MB:0=5000;1=7000" which means 5000 MBps memory bandwidth limit on socket 0 + * and 7000 MBps memory bandwidth limit on socket 1. + * + * For more information about Intel RDT kernel interface: + * https://www.kernel.org/doc/Documentation/x86/intel_rdt_ui.txt + * + * An example for runc: + * Consider a two-socket machine with two L3 caches where the default CBM is + * 0x7ff and the max CBM length is 11 bits, and minimum memory bandwidth of 10% + * with a memory bandwidth granularity of 10%. + * + * Tasks inside the container only have access to the "upper" 7/11 of L3 cache + * on socket 0 and the "lower" 5/11 L3 cache on socket 1, and may use a + * maximum memory bandwidth of 20% on socket 0 and 70% on socket 1. + * + * "linux": { + * "intelRdt": { + * "l3CacheSchema": "L3:0=7f0;1=1f", + * "memBwSchema": "MB:0=20;1=70" + * } + * } + */ + +type Manager interface { + // Applies Intel RDT configuration to the process with the specified pid + Apply(pid int) error + + // Returns statistics for Intel RDT + GetStats() (*Stats, error) + + // Destroys the Intel RDT 'container_id' group + Destroy() error + + // Returns Intel RDT path to save in a state file and to be able to + // restore the object later + GetPath() string + + // Set Intel RDT "resource control" filesystem as configured. + Set(container *configs.Config) error +} + +// This implements interface Manager +type intelRdtManager struct { + mu sync.Mutex + config *configs.Config + id string + path string +} + +func NewManager(config *configs.Config, id string, path string) Manager { + return &intelRdtManager{ + config: config, + id: id, + path: path, + } +} + +const ( + IntelRdtTasks = "tasks" +) + +var ( + // The absolute root path of the Intel RDT "resource control" filesystem + intelRdtRoot string + intelRdtRootLock sync.Mutex + + // The flag to indicate if Intel RDT/CAT is enabled + catEnabled bool + // The flag to indicate if Intel RDT/MBA is enabled + mbaEnabled bool + // The flag to indicate if Intel RDT/MBA Software Controller is enabled + mbaScEnabled bool + + // For Intel RDT initialization + initOnce sync.Once +) + +type intelRdtData struct { + root string + config *configs.Config + pid int +} + +// Check if Intel RDT sub-features are enabled in featuresInit() +func featuresInit() { + initOnce.Do(func() { + // 1. Check if hardware and kernel support Intel RDT sub-features + flagsSet, err := parseCpuInfoFile("/proc/cpuinfo") + if err != nil { + return + } + + // 2. Check if Intel RDT "resource control" filesystem is mounted + // The user guarantees to mount the filesystem + if !isIntelRdtMounted() { + return + } + + // 3. Double check if Intel RDT sub-features are available in + // "resource control" filesystem. Intel RDT sub-features can be + // selectively disabled or enabled by kernel command line + // (e.g., rdt=!l3cat,mba) in 4.14 and newer kernel + if flagsSet.CAT { + if _, err := os.Stat(filepath.Join(intelRdtRoot, "info", "L3")); err == nil { + catEnabled = true + } + } + if mbaScEnabled { + // We confirm MBA Software Controller is enabled in step 2, + // MBA should be enabled because MBA Software Controller + // depends on MBA + mbaEnabled = true + } else if flagsSet.MBA { + if _, err := os.Stat(filepath.Join(intelRdtRoot, "info", "MB")); err == nil { + mbaEnabled = true + } + } + if flagsSet.MBMTotal || flagsSet.MBMLocal || flagsSet.CMT { + if _, err := os.Stat(filepath.Join(intelRdtRoot, "info", "L3_MON")); err != nil { + return + } + enabledMonFeatures, err = getMonFeatures(intelRdtRoot) + if err != nil { + return + } + if enabledMonFeatures.mbmTotalBytes || enabledMonFeatures.mbmLocalBytes { + mbmEnabled = true + } + if enabledMonFeatures.llcOccupancy { + cmtEnabled = true + } + } + }) +} + +// Return the mount point path of Intel RDT "resource control" filesysem +func findIntelRdtMountpointDir(f io.Reader) (string, error) { + mi, err := mountinfo.GetMountsFromReader(f, func(m *mountinfo.Info) (bool, bool) { + // similar to mountinfo.FSTypeFilter but stops after the first match + if m.FSType == "resctrl" { + return false, true // don't skip, stop + } + return true, false // skip, keep going + }) + if err != nil { + return "", err + } + if len(mi) < 1 { + return "", NewNotFoundError("Intel RDT") + } + + // Check if MBA Software Controller is enabled through mount option "-o mba_MBps" + if strings.Contains(","+mi[0].VFSOptions+",", ",mba_MBps,") { + mbaScEnabled = true + } + + return mi[0].Mountpoint, nil +} + +// Gets the root path of Intel RDT "resource control" filesystem +func getIntelRdtRoot() (string, error) { + intelRdtRootLock.Lock() + defer intelRdtRootLock.Unlock() + + if intelRdtRoot != "" { + return intelRdtRoot, nil + } + + f, err := os.Open("/proc/self/mountinfo") + if err != nil { + return "", err + } + root, err := findIntelRdtMountpointDir(f) + f.Close() + if err != nil { + return "", err + } + + if _, err := os.Stat(root); err != nil { + return "", err + } + + intelRdtRoot = root + return intelRdtRoot, nil +} + +func isIntelRdtMounted() bool { + _, err := getIntelRdtRoot() + return err == nil +} + +type cpuInfoFlags struct { + CAT bool // Cache Allocation Technology + MBA bool // Memory Bandwidth Allocation + + // Memory Bandwidth Monitoring related. + MBMTotal bool + MBMLocal bool + + CMT bool // Cache Monitoring Technology +} + +func parseCpuInfoFile(path string) (cpuInfoFlags, error) { + infoFlags := cpuInfoFlags{} + + f, err := os.Open(path) + if err != nil { + return infoFlags, err + } + defer f.Close() + + s := bufio.NewScanner(f) + for s.Scan() { + line := s.Text() + + // Search "cat_l3" and "mba" flags in first "flags" line + if strings.HasPrefix(line, "flags") { + flags := strings.Split(line, " ") + // "cat_l3" flag for CAT and "mba" flag for MBA + for _, flag := range flags { + switch flag { + case "cat_l3": + infoFlags.CAT = true + case "mba": + infoFlags.MBA = true + case "cqm_mbm_total": + infoFlags.MBMTotal = true + case "cqm_mbm_local": + infoFlags.MBMLocal = true + case "cqm_occup_llc": + infoFlags.CMT = true + } + } + return infoFlags, nil + } + } + if err := s.Err(); err != nil { + return infoFlags, err + } + + return infoFlags, nil +} + +func parseUint(s string, base, bitSize int) (uint64, error) { + value, err := strconv.ParseUint(s, base, bitSize) + if err != nil { + intValue, intErr := strconv.ParseInt(s, base, bitSize) + // 1. Handle negative values greater than MinInt64 (and) + // 2. Handle negative values lesser than MinInt64 + if intErr == nil && intValue < 0 { + return 0, nil + } else if intErr != nil && intErr.(*strconv.NumError).Err == strconv.ErrRange && intValue < 0 { + return 0, nil + } + + return value, err + } + + return value, nil +} + +// Gets a single uint64 value from the specified file. +func getIntelRdtParamUint(path, file string) (uint64, error) { + fileName := filepath.Join(path, file) + contents, err := ioutil.ReadFile(fileName) + if err != nil { + return 0, err + } + + res, err := parseUint(string(bytes.TrimSpace(contents)), 10, 64) + if err != nil { + return res, fmt.Errorf("unable to parse %q as a uint from file %q", string(contents), fileName) + } + return res, nil +} + +// Gets a string value from the specified file +func getIntelRdtParamString(path, file string) (string, error) { + contents, err := ioutil.ReadFile(filepath.Join(path, file)) + if err != nil { + return "", err + } + + return string(bytes.TrimSpace(contents)), nil +} + +func writeFile(dir, file, data string) error { + if dir == "" { + return fmt.Errorf("no such directory for %s", file) + } + if err := ioutil.WriteFile(filepath.Join(dir, file), []byte(data+"\n"), 0o600); err != nil { + return fmt.Errorf("failed to write %v to %v: %v", data, file, err) + } + return nil +} + +func getIntelRdtData(c *configs.Config, pid int) (*intelRdtData, error) { + rootPath, err := getIntelRdtRoot() + if err != nil { + return nil, err + } + return &intelRdtData{ + root: rootPath, + config: c, + pid: pid, + }, nil +} + +// Get the read-only L3 cache information +func getL3CacheInfo() (*L3CacheInfo, error) { + l3CacheInfo := &L3CacheInfo{} + + rootPath, err := getIntelRdtRoot() + if err != nil { + return l3CacheInfo, err + } + + path := filepath.Join(rootPath, "info", "L3") + cbmMask, err := getIntelRdtParamString(path, "cbm_mask") + if err != nil { + return l3CacheInfo, err + } + minCbmBits, err := getIntelRdtParamUint(path, "min_cbm_bits") + if err != nil { + return l3CacheInfo, err + } + numClosids, err := getIntelRdtParamUint(path, "num_closids") + if err != nil { + return l3CacheInfo, err + } + + l3CacheInfo.CbmMask = cbmMask + l3CacheInfo.MinCbmBits = minCbmBits + l3CacheInfo.NumClosids = numClosids + + return l3CacheInfo, nil +} + +// Get the read-only memory bandwidth information +func getMemBwInfo() (*MemBwInfo, error) { + memBwInfo := &MemBwInfo{} + + rootPath, err := getIntelRdtRoot() + if err != nil { + return memBwInfo, err + } + + path := filepath.Join(rootPath, "info", "MB") + bandwidthGran, err := getIntelRdtParamUint(path, "bandwidth_gran") + if err != nil { + return memBwInfo, err + } + delayLinear, err := getIntelRdtParamUint(path, "delay_linear") + if err != nil { + return memBwInfo, err + } + minBandwidth, err := getIntelRdtParamUint(path, "min_bandwidth") + if err != nil { + return memBwInfo, err + } + numClosids, err := getIntelRdtParamUint(path, "num_closids") + if err != nil { + return memBwInfo, err + } + + memBwInfo.BandwidthGran = bandwidthGran + memBwInfo.DelayLinear = delayLinear + memBwInfo.MinBandwidth = minBandwidth + memBwInfo.NumClosids = numClosids + + return memBwInfo, nil +} + +// Get diagnostics for last filesystem operation error from file info/last_cmd_status +func getLastCmdStatus() (string, error) { + rootPath, err := getIntelRdtRoot() + if err != nil { + return "", err + } + + path := filepath.Join(rootPath, "info") + lastCmdStatus, err := getIntelRdtParamString(path, "last_cmd_status") + if err != nil { + return "", err + } + + return lastCmdStatus, nil +} + +// WriteIntelRdtTasks writes the specified pid into the "tasks" file +func WriteIntelRdtTasks(dir string, pid int) error { + if dir == "" { + return fmt.Errorf("no such directory for %s", IntelRdtTasks) + } + + // Don't attach any pid if -1 is specified as a pid + if pid != -1 { + if err := ioutil.WriteFile(filepath.Join(dir, IntelRdtTasks), []byte(strconv.Itoa(pid)), 0o600); err != nil { + return fmt.Errorf("failed to write %v to %v: %v", pid, IntelRdtTasks, err) + } + } + return nil +} + +// Check if Intel RDT/CAT is enabled +func IsCATEnabled() bool { + featuresInit() + return catEnabled +} + +// Check if Intel RDT/MBA is enabled +func IsMBAEnabled() bool { + featuresInit() + return mbaEnabled +} + +// Check if Intel RDT/MBA Software Controller is enabled +func IsMBAScEnabled() bool { + featuresInit() + return mbaScEnabled +} + +// Get the 'container_id' path in Intel RDT "resource control" filesystem +func GetIntelRdtPath(id string) (string, error) { + rootPath, err := getIntelRdtRoot() + if err != nil { + return "", err + } + + path := filepath.Join(rootPath, id) + return path, nil +} + +// Applies Intel RDT configuration to the process with the specified pid +func (m *intelRdtManager) Apply(pid int) (err error) { + // If intelRdt is not specified in config, we do nothing + if m.config.IntelRdt == nil { + return nil + } + d, err := getIntelRdtData(m.config, pid) + if err != nil && !IsNotFound(err) { + return err + } + + m.mu.Lock() + defer m.mu.Unlock() + path, err := d.join(m.id) + if err != nil { + return err + } + + m.path = path + return nil +} + +// Destroys the Intel RDT 'container_id' group +func (m *intelRdtManager) Destroy() error { + m.mu.Lock() + defer m.mu.Unlock() + if err := os.RemoveAll(m.GetPath()); err != nil { + return err + } + m.path = "" + return nil +} + +// Returns Intel RDT path to save in a state file and to be able to +// restore the object later +func (m *intelRdtManager) GetPath() string { + if m.path == "" { + m.path, _ = GetIntelRdtPath(m.id) + } + return m.path +} + +// Returns statistics for Intel RDT +func (m *intelRdtManager) GetStats() (*Stats, error) { + // If intelRdt is not specified in config + if m.config.IntelRdt == nil { + return nil, nil + } + + m.mu.Lock() + defer m.mu.Unlock() + stats := NewStats() + + rootPath, err := getIntelRdtRoot() + if err != nil { + return nil, err + } + // The read-only L3 cache and memory bandwidth schemata in root + tmpRootStrings, err := getIntelRdtParamString(rootPath, "schemata") + if err != nil { + return nil, err + } + schemaRootStrings := strings.Split(tmpRootStrings, "\n") + + // The L3 cache and memory bandwidth schemata in 'container_id' group + containerPath := m.GetPath() + tmpStrings, err := getIntelRdtParamString(containerPath, "schemata") + if err != nil { + return nil, err + } + schemaStrings := strings.Split(tmpStrings, "\n") + + if IsCATEnabled() { + // The read-only L3 cache information + l3CacheInfo, err := getL3CacheInfo() + if err != nil { + return nil, err + } + stats.L3CacheInfo = l3CacheInfo + + // The read-only L3 cache schema in root + for _, schemaRoot := range schemaRootStrings { + if strings.Contains(schemaRoot, "L3") { + stats.L3CacheSchemaRoot = strings.TrimSpace(schemaRoot) + } + } + + // The L3 cache schema in 'container_id' group + for _, schema := range schemaStrings { + if strings.Contains(schema, "L3") { + stats.L3CacheSchema = strings.TrimSpace(schema) + } + } + } + + if IsMBAEnabled() { + // The read-only memory bandwidth information + memBwInfo, err := getMemBwInfo() + if err != nil { + return nil, err + } + stats.MemBwInfo = memBwInfo + + // The read-only memory bandwidth information + for _, schemaRoot := range schemaRootStrings { + if strings.Contains(schemaRoot, "MB") { + stats.MemBwSchemaRoot = strings.TrimSpace(schemaRoot) + } + } + + // The memory bandwidth schema in 'container_id' group + for _, schema := range schemaStrings { + if strings.Contains(schema, "MB") { + stats.MemBwSchema = strings.TrimSpace(schema) + } + } + } + + if IsMBMEnabled() || IsCMTEnabled() { + err = getMonitoringStats(containerPath, stats) + if err != nil { + return nil, err + } + } + + return stats, nil +} + +// Set Intel RDT "resource control" filesystem as configured. +func (m *intelRdtManager) Set(container *configs.Config) error { + // About L3 cache schema: + // It has allocation bitmasks/values for L3 cache on each socket, + // which contains L3 cache id and capacity bitmask (CBM). + // Format: "L3:=;=;..." + // For example, on a two-socket machine, the schema line could be: + // L3:0=ff;1=c0 + // which means L3 cache id 0's CBM is 0xff, and L3 cache id 1's CBM + // is 0xc0. + // + // The valid L3 cache CBM is a *contiguous bits set* and number of + // bits that can be set is less than the max bit. The max bits in the + // CBM is varied among supported Intel CPU models. Kernel will check + // if it is valid when writing. e.g., default value 0xfffff in root + // indicates the max bits of CBM is 20 bits, which mapping to entire + // L3 cache capacity. Some valid CBM values to set in a group: + // 0xf, 0xf0, 0x3ff, 0x1f00 and etc. + // + // + // About memory bandwidth schema: + // It has allocation values for memory bandwidth on each socket, which + // contains L3 cache id and memory bandwidth. + // Format: "MB:=bandwidth0;=bandwidth1;..." + // For example, on a two-socket machine, the schema line could be: + // "MB:0=20;1=70" + // + // The minimum bandwidth percentage value for each CPU model is + // predefined and can be looked up through "info/MB/min_bandwidth". + // The bandwidth granularity that is allocated is also dependent on + // the CPU model and can be looked up at "info/MB/bandwidth_gran". + // The available bandwidth control steps are: min_bw + N * bw_gran. + // Intermediate values are rounded to the next control step available + // on the hardware. + // + // If MBA Software Controller is enabled through mount option + // "-o mba_MBps": mount -t resctrl resctrl -o mba_MBps /sys/fs/resctrl + // We could specify memory bandwidth in "MBps" (Mega Bytes per second) + // unit instead of "percentages". The kernel underneath would use a + // software feedback mechanism or a "Software Controller" which reads + // the actual bandwidth using MBM counters and adjust the memory + // bandwidth percentages to ensure: + // "actual memory bandwidth < user specified memory bandwidth". + // + // For example, on a two-socket machine, the schema line could be + // "MB:0=5000;1=7000" which means 5000 MBps memory bandwidth limit on + // socket 0 and 7000 MBps memory bandwidth limit on socket 1. + if container.IntelRdt != nil { + path := m.GetPath() + l3CacheSchema := container.IntelRdt.L3CacheSchema + memBwSchema := container.IntelRdt.MemBwSchema + + // Write a single joint schema string to schemata file + if l3CacheSchema != "" && memBwSchema != "" { + if err := writeFile(path, "schemata", l3CacheSchema+"\n"+memBwSchema); err != nil { + return NewLastCmdError(err) + } + } + + // Write only L3 cache schema string to schemata file + if l3CacheSchema != "" && memBwSchema == "" { + if err := writeFile(path, "schemata", l3CacheSchema); err != nil { + return NewLastCmdError(err) + } + } + + // Write only memory bandwidth schema string to schemata file + if l3CacheSchema == "" && memBwSchema != "" { + if err := writeFile(path, "schemata", memBwSchema); err != nil { + return NewLastCmdError(err) + } + } + } + + return nil +} + +func (raw *intelRdtData) join(id string) (string, error) { + path := filepath.Join(raw.root, id) + if err := os.MkdirAll(path, 0o755); err != nil { + return "", NewLastCmdError(err) + } + + if err := WriteIntelRdtTasks(path, raw.pid); err != nil { + return "", NewLastCmdError(err) + } + return path, nil +} + +type NotFoundError struct { + ResourceControl string +} + +func (e *NotFoundError) Error() string { + return fmt.Sprintf("mountpoint for %s not found", e.ResourceControl) +} + +func NewNotFoundError(res string) error { + return &NotFoundError{ + ResourceControl: res, + } +} + +func IsNotFound(err error) bool { + if err == nil { + return false + } + _, ok := err.(*NotFoundError) + return ok +} + +type LastCmdError struct { + LastCmdStatus string + Err error +} + +func (e *LastCmdError) Error() string { + return e.Err.Error() + ", last_cmd_status: " + e.LastCmdStatus +} + +func NewLastCmdError(err error) error { + lastCmdStatus, err1 := getLastCmdStatus() + if err1 == nil { + return &LastCmdError{ + LastCmdStatus: lastCmdStatus, + Err: err, + } + } + return err +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/mbm.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/mbm.go new file mode 100644 index 000000000000..93063ee01905 --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/mbm.go @@ -0,0 +1,35 @@ +// +build linux + +package intelrdt + +var ( + // The flag to indicate if Intel RDT/MBM is enabled + mbmEnabled bool +) + +// Check if Intel RDT/MBM is enabled. +func IsMBMEnabled() bool { + featuresInit() + return mbmEnabled +} + +func getMBMNumaNodeStats(numaPath string) (*MBMNumaNodeStats, error) { + stats := &MBMNumaNodeStats{} + if enabledMonFeatures.mbmTotalBytes { + mbmTotalBytes, err := getIntelRdtParamUint(numaPath, "mbm_total_bytes") + if err != nil { + return nil, err + } + stats.MBMTotalBytes = mbmTotalBytes + } + + if enabledMonFeatures.mbmLocalBytes { + mbmLocalBytes, err := getIntelRdtParamUint(numaPath, "mbm_local_bytes") + if err != nil { + return nil, err + } + stats.MBMLocalBytes = mbmLocalBytes + } + + return stats, nil +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/monitoring.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/monitoring.go new file mode 100644 index 000000000000..78c2f624c960 --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/monitoring.go @@ -0,0 +1,86 @@ +package intelrdt + +import ( + "bufio" + "io" + "io/ioutil" + "os" + "path/filepath" + + "github.com/sirupsen/logrus" +) + +var ( + enabledMonFeatures monFeatures +) + +type monFeatures struct { + mbmTotalBytes bool + mbmLocalBytes bool + llcOccupancy bool +} + +func getMonFeatures(intelRdtRoot string) (monFeatures, error) { + file, err := os.Open(filepath.Join(intelRdtRoot, "info", "L3_MON", "mon_features")) + if err != nil { + return monFeatures{}, err + } + defer file.Close() + return parseMonFeatures(file) +} + +func parseMonFeatures(reader io.Reader) (monFeatures, error) { + scanner := bufio.NewScanner(reader) + + monFeatures := monFeatures{} + + for scanner.Scan() { + switch feature := scanner.Text(); feature { + case "mbm_total_bytes": + monFeatures.mbmTotalBytes = true + case "mbm_local_bytes": + monFeatures.mbmLocalBytes = true + case "llc_occupancy": + monFeatures.llcOccupancy = true + default: + logrus.Warnf("Unsupported Intel RDT monitoring feature: %s", feature) + } + } + + return monFeatures, scanner.Err() +} + +func getMonitoringStats(containerPath string, stats *Stats) error { + numaFiles, err := ioutil.ReadDir(filepath.Join(containerPath, "mon_data")) + if err != nil { + return err + } + + var mbmStats []MBMNumaNodeStats + var cmtStats []CMTNumaNodeStats + + for _, file := range numaFiles { + if file.IsDir() { + numaPath := filepath.Join(containerPath, "mon_data", file.Name()) + if IsMBMEnabled() { + numaMBMStats, err := getMBMNumaNodeStats(numaPath) + if err != nil { + return err + } + mbmStats = append(mbmStats, *numaMBMStats) + } + if IsCMTEnabled() { + numaCMTStats, err := getCMTNumaNodeStats(numaPath) + if err != nil { + return err + } + cmtStats = append(cmtStats, *numaCMTStats) + } + } + } + + stats.MBMStats = &mbmStats + stats.CMTStats = &cmtStats + + return err +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/stats.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/stats.go new file mode 100644 index 000000000000..70df0d14e6ce --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/stats.go @@ -0,0 +1,59 @@ +// +build linux + +package intelrdt + +type L3CacheInfo struct { + CbmMask string `json:"cbm_mask,omitempty"` + MinCbmBits uint64 `json:"min_cbm_bits,omitempty"` + NumClosids uint64 `json:"num_closids,omitempty"` +} + +type MemBwInfo struct { + BandwidthGran uint64 `json:"bandwidth_gran,omitempty"` + DelayLinear uint64 `json:"delay_linear,omitempty"` + MinBandwidth uint64 `json:"min_bandwidth,omitempty"` + NumClosids uint64 `json:"num_closids,omitempty"` +} + +type MBMNumaNodeStats struct { + // The 'mbm_total_bytes' in 'container_id' group. + MBMTotalBytes uint64 `json:"mbm_total_bytes"` + + // The 'mbm_local_bytes' in 'container_id' group. + MBMLocalBytes uint64 `json:"mbm_local_bytes"` +} + +type CMTNumaNodeStats struct { + // The 'llc_occupancy' in 'container_id' group. + LLCOccupancy uint64 `json:"llc_occupancy"` +} + +type Stats struct { + // The read-only L3 cache information + L3CacheInfo *L3CacheInfo `json:"l3_cache_info,omitempty"` + + // The read-only L3 cache schema in root + L3CacheSchemaRoot string `json:"l3_cache_schema_root,omitempty"` + + // The L3 cache schema in 'container_id' group + L3CacheSchema string `json:"l3_cache_schema,omitempty"` + + // The read-only memory bandwidth information + MemBwInfo *MemBwInfo `json:"mem_bw_info,omitempty"` + + // The read-only memory bandwidth schema in root + MemBwSchemaRoot string `json:"mem_bw_schema_root,omitempty"` + + // The memory bandwidth schema in 'container_id' group + MemBwSchema string `json:"mem_bw_schema,omitempty"` + + // The memory bandwidth monitoring statistics from NUMA nodes in 'container_id' group + MBMStats *[]MBMNumaNodeStats `json:"mbm_stats,omitempty"` + + // The cache monitoring technology statistics from NUMA nodes in 'container_id' group + CMTStats *[]CMTNumaNodeStats `json:"cmt_stats,omitempty"` +} + +func NewStats() *Stats { + return &Stats{} +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/keys/keyctl.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/keys/keyctl.go new file mode 100644 index 000000000000..e73af7ae2dca --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/keys/keyctl.go @@ -0,0 +1,47 @@ +// +build linux + +package keys + +import ( + "strconv" + "strings" + + "github.com/pkg/errors" + + "golang.org/x/sys/unix" +) + +type KeySerial uint32 + +func JoinSessionKeyring(name string) (KeySerial, error) { + sessKeyId, err := unix.KeyctlJoinSessionKeyring(name) + if err != nil { + return 0, errors.Wrap(err, "create session key") + } + return KeySerial(sessKeyId), nil +} + +// ModKeyringPerm modifies permissions on a keyring by reading the current permissions, +// anding the bits with the given mask (clearing permissions) and setting +// additional permission bits +func ModKeyringPerm(ringId KeySerial, mask, setbits uint32) error { + dest, err := unix.KeyctlString(unix.KEYCTL_DESCRIBE, int(ringId)) + if err != nil { + return err + } + + res := strings.Split(dest, ";") + if len(res) < 5 { + return errors.New("Destination buffer for key description is too small") + } + + // parse permissions + perm64, err := strconv.ParseUint(res[3], 16, 32) + if err != nil { + return err + } + + perm := (uint32(perm64) & mask) | setbits + + return unix.KeyctlSetperm(int(ringId), perm) +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/logs/logs.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/logs/logs.go new file mode 100644 index 000000000000..1077e7b01450 --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/logs/logs.go @@ -0,0 +1,102 @@ +package logs + +import ( + "bufio" + "encoding/json" + "fmt" + "io" + "os" + "strconv" + "sync" + + "github.com/sirupsen/logrus" +) + +var ( + configureMutex = sync.Mutex{} + // loggingConfigured will be set once logging has been configured via invoking `ConfigureLogging`. + // Subsequent invocations of `ConfigureLogging` would be no-op + loggingConfigured = false +) + +type Config struct { + LogLevel logrus.Level + LogFormat string + LogFilePath string + LogPipeFd string +} + +func ForwardLogs(logPipe io.Reader) { + lineReader := bufio.NewReader(logPipe) + for { + line, err := lineReader.ReadBytes('\n') + if len(line) > 0 { + processEntry(line) + } + if err == io.EOF { + logrus.Debugf("log pipe has been closed: %+v", err) + return + } + if err != nil { + logrus.Errorf("log pipe read error: %+v", err) + } + } +} + +func processEntry(text []byte) { + type jsonLog struct { + Level string `json:"level"` + Msg string `json:"msg"` + } + + var jl jsonLog + if err := json.Unmarshal(text, &jl); err != nil { + logrus.Errorf("failed to decode %q to json: %+v", text, err) + return + } + + lvl, err := logrus.ParseLevel(jl.Level) + if err != nil { + logrus.Errorf("failed to parse log level %q: %v\n", jl.Level, err) + return + } + logrus.StandardLogger().Logf(lvl, jl.Msg) +} + +func ConfigureLogging(config Config) error { + configureMutex.Lock() + defer configureMutex.Unlock() + + if loggingConfigured { + logrus.Debug("logging has already been configured") + return nil + } + + logrus.SetLevel(config.LogLevel) + + if config.LogPipeFd != "" { + logPipeFdInt, err := strconv.Atoi(config.LogPipeFd) + if err != nil { + return fmt.Errorf("failed to convert _LIBCONTAINER_LOGPIPE environment variable value %q to int: %v", config.LogPipeFd, err) + } + logrus.SetOutput(os.NewFile(uintptr(logPipeFdInt), "logpipe")) + } else if config.LogFilePath != "" { + f, err := os.OpenFile(config.LogFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND|os.O_SYNC, 0644) + if err != nil { + return err + } + logrus.SetOutput(f) + } + + switch config.LogFormat { + case "text": + // retain logrus's default. + case "json": + logrus.SetFormatter(new(logrus.JSONFormatter)) + default: + return fmt.Errorf("unknown log-format %q", config.LogFormat) + } + + loggingConfigured = true + return nil +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/message_linux.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/message_linux.go new file mode 100644 index 000000000000..1d4f5033aa2f --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/message_linux.go @@ -0,0 +1,89 @@ +// +build linux + +package libcontainer + +import ( + "github.com/vishvananda/netlink/nl" + "golang.org/x/sys/unix" +) + +// list of known message types we want to send to bootstrap program +// The number is randomly chosen to not conflict with known netlink types +const ( + InitMsg uint16 = 62000 + CloneFlagsAttr uint16 = 27281 + NsPathsAttr uint16 = 27282 + UidmapAttr uint16 = 27283 + GidmapAttr uint16 = 27284 + SetgroupAttr uint16 = 27285 + OomScoreAdjAttr uint16 = 27286 + RootlessEUIDAttr uint16 = 27287 + UidmapPathAttr uint16 = 27288 + GidmapPathAttr uint16 = 27289 +) + +type Int32msg struct { + Type uint16 + Value uint32 +} + +// Serialize serializes the message. +// Int32msg has the following representation +// | nlattr len | nlattr type | +// | uint32 value | +func (msg *Int32msg) Serialize() []byte { + buf := make([]byte, msg.Len()) + native := nl.NativeEndian() + native.PutUint16(buf[0:2], uint16(msg.Len())) + native.PutUint16(buf[2:4], msg.Type) + native.PutUint32(buf[4:8], msg.Value) + return buf +} + +func (msg *Int32msg) Len() int { + return unix.NLA_HDRLEN + 4 +} + +// Bytemsg has the following representation +// | nlattr len | nlattr type | +// | value | pad | +type Bytemsg struct { + Type uint16 + Value []byte +} + +func (msg *Bytemsg) Serialize() []byte { + l := msg.Len() + buf := make([]byte, (l+unix.NLA_ALIGNTO-1) & ^(unix.NLA_ALIGNTO-1)) + native := nl.NativeEndian() + native.PutUint16(buf[0:2], uint16(l)) + native.PutUint16(buf[2:4], msg.Type) + copy(buf[4:], msg.Value) + return buf +} + +func (msg *Bytemsg) Len() int { + return unix.NLA_HDRLEN + len(msg.Value) + 1 // null-terminated +} + +type Boolmsg struct { + Type uint16 + Value bool +} + +func (msg *Boolmsg) Serialize() []byte { + buf := make([]byte, msg.Len()) + native := nl.NativeEndian() + native.PutUint16(buf[0:2], uint16(msg.Len())) + native.PutUint16(buf[2:4], msg.Type) + if msg.Value { + native.PutUint32(buf[4:8], uint32(1)) + } else { + native.PutUint32(buf[4:8], uint32(0)) + } + return buf +} + +func (msg *Boolmsg) Len() int { + return unix.NLA_HDRLEN + 4 // alignment +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/network_linux.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/network_linux.go new file mode 100644 index 000000000000..a0a87b9842af --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/network_linux.go @@ -0,0 +1,103 @@ +// +build linux + +package libcontainer + +import ( + "bytes" + "fmt" + "io/ioutil" + "path/filepath" + "strconv" + + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/types" + "github.com/vishvananda/netlink" +) + +var strategies = map[string]networkStrategy{ + "loopback": &loopback{}, +} + +// networkStrategy represents a specific network configuration for +// a container's networking stack +type networkStrategy interface { + create(*network, int) error + initialize(*network) error + detach(*configs.Network) error + attach(*configs.Network) error +} + +// getStrategy returns the specific network strategy for the +// provided type. +func getStrategy(tpe string) (networkStrategy, error) { + s, exists := strategies[tpe] + if !exists { + return nil, fmt.Errorf("unknown strategy type %q", tpe) + } + return s, nil +} + +// Returns the network statistics for the network interfaces represented by the NetworkRuntimeInfo. +func getNetworkInterfaceStats(interfaceName string) (*types.NetworkInterface, error) { + out := &types.NetworkInterface{Name: interfaceName} + // This can happen if the network runtime information is missing - possible if the + // container was created by an old version of libcontainer. + if interfaceName == "" { + return out, nil + } + type netStatsPair struct { + // Where to write the output. + Out *uint64 + // The network stats file to read. + File string + } + // Ingress for host veth is from the container. Hence tx_bytes stat on the host veth is actually number of bytes received by the container. + netStats := []netStatsPair{ + {Out: &out.RxBytes, File: "tx_bytes"}, + {Out: &out.RxPackets, File: "tx_packets"}, + {Out: &out.RxErrors, File: "tx_errors"}, + {Out: &out.RxDropped, File: "tx_dropped"}, + + {Out: &out.TxBytes, File: "rx_bytes"}, + {Out: &out.TxPackets, File: "rx_packets"}, + {Out: &out.TxErrors, File: "rx_errors"}, + {Out: &out.TxDropped, File: "rx_dropped"}, + } + for _, netStat := range netStats { + data, err := readSysfsNetworkStats(interfaceName, netStat.File) + if err != nil { + return nil, err + } + *(netStat.Out) = data + } + return out, nil +} + +// Reads the specified statistics available under /sys/class/net//statistics +func readSysfsNetworkStats(ethInterface, statsFile string) (uint64, error) { + data, err := ioutil.ReadFile(filepath.Join("/sys/class/net", ethInterface, "statistics", statsFile)) + if err != nil { + return 0, err + } + return strconv.ParseUint(string(bytes.TrimSpace(data)), 10, 64) +} + +// loopback is a network strategy that provides a basic loopback device +type loopback struct { +} + +func (l *loopback) create(n *network, nspid int) error { + return nil +} + +func (l *loopback) initialize(config *network) error { + return netlink.LinkSetUp(&netlink.Device{LinkAttrs: netlink.LinkAttrs{Name: "lo"}}) +} + +func (l *loopback) attach(n *configs.Network) (err error) { + return nil +} + +func (l *loopback) detach(n *configs.Network) (err error) { + return nil +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/notify_linux.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/notify_linux.go new file mode 100644 index 000000000000..d7d1de1ba512 --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/notify_linux.go @@ -0,0 +1,87 @@ +// +build linux + +package libcontainer + +import ( + "errors" + "fmt" + "io/ioutil" + "os" + "path/filepath" + + "golang.org/x/sys/unix" +) + +type PressureLevel uint + +const ( + LowPressure PressureLevel = iota + MediumPressure + CriticalPressure +) + +func registerMemoryEvent(cgDir string, evName string, arg string) (<-chan struct{}, error) { + evFile, err := os.Open(filepath.Join(cgDir, evName)) + if err != nil { + return nil, err + } + fd, err := unix.Eventfd(0, unix.EFD_CLOEXEC) + if err != nil { + evFile.Close() + return nil, err + } + + eventfd := os.NewFile(uintptr(fd), "eventfd") + + eventControlPath := filepath.Join(cgDir, "cgroup.event_control") + data := fmt.Sprintf("%d %d %s", eventfd.Fd(), evFile.Fd(), arg) + if err := ioutil.WriteFile(eventControlPath, []byte(data), 0700); err != nil { + eventfd.Close() + evFile.Close() + return nil, err + } + ch := make(chan struct{}) + go func() { + defer func() { + eventfd.Close() + evFile.Close() + close(ch) + }() + buf := make([]byte, 8) + for { + if _, err := eventfd.Read(buf); err != nil { + return + } + // When a cgroup is destroyed, an event is sent to eventfd. + // So if the control path is gone, return instead of notifying. + if _, err := os.Lstat(eventControlPath); os.IsNotExist(err) { + return + } + ch <- struct{}{} + } + }() + return ch, nil +} + +// notifyOnOOM returns channel on which you can expect event about OOM, +// if process died without OOM this channel will be closed. +func notifyOnOOM(dir string) (<-chan struct{}, error) { + if dir == "" { + return nil, errors.New("memory controller missing") + } + + return registerMemoryEvent(dir, "memory.oom_control", "") +} + +func notifyMemoryPressure(dir string, level PressureLevel) (<-chan struct{}, error) { + if dir == "" { + return nil, errors.New("memory controller missing") + } + + if level > CriticalPressure { + return nil, fmt.Errorf("invalid pressure level %d", level) + } + + levelStr := []string{"low", "medium", "critical"}[level] + return registerMemoryEvent(dir, "memory.pressure_level", levelStr) +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/notify_linux_v2.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/notify_linux_v2.go new file mode 100644 index 000000000000..cdab10ed609e --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/notify_linux_v2.go @@ -0,0 +1,102 @@ +// +build linux + +package libcontainer + +import ( + "io/ioutil" + "path/filepath" + "strconv" + "strings" + "unsafe" + + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" +) + +func getValueFromCgroup(path, key string) (int, error) { + content, err := ioutil.ReadFile(path) + if err != nil { + return 0, err + } + + lines := strings.Split(string(content), "\n") + for _, line := range lines { + arr := strings.Split(line, " ") + if len(arr) == 2 && arr[0] == key { + return strconv.Atoi(arr[1]) + } + } + return 0, nil +} + +func registerMemoryEventV2(cgDir, evName, cgEvName string) (<-chan struct{}, error) { + eventControlPath := filepath.Join(cgDir, evName) + cgEvPath := filepath.Join(cgDir, cgEvName) + fd, err := unix.InotifyInit() + if err != nil { + return nil, errors.Wrap(err, "unable to init inotify") + } + // watching oom kill + evFd, err := unix.InotifyAddWatch(fd, eventControlPath, unix.IN_MODIFY) + if err != nil { + unix.Close(fd) + return nil, errors.Wrap(err, "unable to add inotify watch") + } + // Because no `unix.IN_DELETE|unix.IN_DELETE_SELF` event for cgroup file system, so watching all process exited + cgFd, err := unix.InotifyAddWatch(fd, cgEvPath, unix.IN_MODIFY) + if err != nil { + unix.Close(fd) + return nil, errors.Wrap(err, "unable to add inotify watch") + } + ch := make(chan struct{}) + go func() { + var ( + buffer [unix.SizeofInotifyEvent + unix.PathMax + 1]byte + offset uint32 + ) + defer func() { + unix.Close(fd) + close(ch) + }() + + for { + n, err := unix.Read(fd, buffer[:]) + if err != nil { + logrus.Warnf("unable to read event data from inotify, got error: %v", err) + return + } + if n < unix.SizeofInotifyEvent { + logrus.Warnf("we should read at least %d bytes from inotify, but got %d bytes.", unix.SizeofInotifyEvent, n) + return + } + offset = 0 + for offset <= uint32(n-unix.SizeofInotifyEvent) { + rawEvent := (*unix.InotifyEvent)(unsafe.Pointer(&buffer[offset])) + offset += unix.SizeofInotifyEvent + uint32(rawEvent.Len) + if rawEvent.Mask&unix.IN_MODIFY != unix.IN_MODIFY { + continue + } + switch int(rawEvent.Wd) { + case evFd: + oom, err := getValueFromCgroup(eventControlPath, "oom_kill") + if err != nil || oom > 0 { + ch <- struct{}{} + } + case cgFd: + pids, err := getValueFromCgroup(cgEvPath, "populated") + if err != nil || pids == 0 { + return + } + } + } + } + }() + return ch, nil +} + +// notifyOnOOMV2 returns channel on which you can expect event about OOM, +// if process died without OOM this channel will be closed. +func notifyOnOOMV2(path string) (<-chan struct{}, error) { + return registerMemoryEventV2(path, "memory.events", "cgroup.events") +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/process.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/process.go new file mode 100644 index 000000000000..d3e472a4fdb9 --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/process.go @@ -0,0 +1,115 @@ +package libcontainer + +import ( + "fmt" + "io" + "math" + "os" + + "github.com/opencontainers/runc/libcontainer/configs" +) + +type processOperations interface { + wait() (*os.ProcessState, error) + signal(sig os.Signal) error + pid() int +} + +// Process specifies the configuration and IO for a process inside +// a container. +type Process struct { + // The command to be run followed by any arguments. + Args []string + + // Env specifies the environment variables for the process. + Env []string + + // User will set the uid and gid of the executing process running inside the container + // local to the container's user and group configuration. + User string + + // AdditionalGroups specifies the gids that should be added to supplementary groups + // in addition to those that the user belongs to. + AdditionalGroups []string + + // Cwd will change the processes current working directory inside the container's rootfs. + Cwd string + + // Stdin is a pointer to a reader which provides the standard input stream. + Stdin io.Reader + + // Stdout is a pointer to a writer which receives the standard output stream. + Stdout io.Writer + + // Stderr is a pointer to a writer which receives the standard error stream. + Stderr io.Writer + + // ExtraFiles specifies additional open files to be inherited by the container + ExtraFiles []*os.File + + // Initial sizings for the console + ConsoleWidth uint16 + ConsoleHeight uint16 + + // Capabilities specify the capabilities to keep when executing the process inside the container + // All capabilities not specified will be dropped from the processes capability mask + Capabilities *configs.Capabilities + + // AppArmorProfile specifies the profile to apply to the process and is + // changed at the time the process is execed + AppArmorProfile string + + // Label specifies the label to apply to the process. It is commonly used by selinux + Label string + + // NoNewPrivileges controls whether processes can gain additional privileges. + NoNewPrivileges *bool + + // Rlimits specifies the resource limits, such as max open files, to set in the container + // If Rlimits are not set, the container will inherit rlimits from the parent process + Rlimits []configs.Rlimit + + // ConsoleSocket provides the masterfd console. + ConsoleSocket *os.File + + // Init specifies whether the process is the first process in the container. + Init bool + + ops processOperations + + LogLevel string +} + +// Wait waits for the process to exit. +// Wait releases any resources associated with the Process +func (p Process) Wait() (*os.ProcessState, error) { + if p.ops == nil { + return nil, newGenericError(fmt.Errorf("invalid process"), NoProcessOps) + } + return p.ops.wait() +} + +// Pid returns the process ID +func (p Process) Pid() (int, error) { + // math.MinInt32 is returned here, because it's invalid value + // for the kill() system call. + if p.ops == nil { + return math.MinInt32, newGenericError(fmt.Errorf("invalid process"), NoProcessOps) + } + return p.ops.pid(), nil +} + +// Signal sends a signal to the Process. +func (p Process) Signal(sig os.Signal) error { + if p.ops == nil { + return newGenericError(fmt.Errorf("invalid process"), NoProcessOps) + } + return p.ops.signal(sig) +} + +// IO holds the process's STDIO +type IO struct { + Stdin io.WriteCloser + Stdout io.ReadCloser + Stderr io.ReadCloser +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/process_linux.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/process_linux.go new file mode 100644 index 000000000000..834268b99571 --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/process_linux.go @@ -0,0 +1,651 @@ +// +build linux + +package libcontainer + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "os" + "os/exec" + "path/filepath" + "strconv" + "time" + + "github.com/opencontainers/runc/libcontainer/cgroups" + "github.com/opencontainers/runc/libcontainer/cgroups/fs2" + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/intelrdt" + "github.com/opencontainers/runc/libcontainer/logs" + "github.com/opencontainers/runc/libcontainer/system" + "github.com/opencontainers/runc/libcontainer/utils" + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" +) + +// Synchronisation value for cgroup namespace setup. +// The same constant is defined in nsexec.c as "CREATECGROUPNS". +const createCgroupns = 0x80 + +type parentProcess interface { + // pid returns the pid for the running process. + pid() int + + // start starts the process execution. + start() error + + // send a SIGKILL to the process and wait for the exit. + terminate() error + + // wait waits on the process returning the process state. + wait() (*os.ProcessState, error) + + // startTime returns the process start time. + startTime() (uint64, error) + + signal(os.Signal) error + + externalDescriptors() []string + + setExternalDescriptors(fds []string) + + forwardChildLogs() +} + +type filePair struct { + parent *os.File + child *os.File +} + +type setnsProcess struct { + cmd *exec.Cmd + messageSockPair filePair + logFilePair filePair + cgroupPaths map[string]string + rootlessCgroups bool + intelRdtPath string + config *initConfig + fds []string + process *Process + bootstrapData io.Reader + initProcessPid int +} + +func (p *setnsProcess) startTime() (uint64, error) { + stat, err := system.Stat(p.pid()) + return stat.StartTime, err +} + +func (p *setnsProcess) signal(sig os.Signal) error { + s, ok := sig.(unix.Signal) + if !ok { + return errors.New("os: unsupported signal type") + } + return unix.Kill(p.pid(), s) +} + +func (p *setnsProcess) start() (retErr error) { + defer p.messageSockPair.parent.Close() + err := p.cmd.Start() + // close the write-side of the pipes (controlled by child) + p.messageSockPair.child.Close() + p.logFilePair.child.Close() + if err != nil { + return newSystemErrorWithCause(err, "starting setns process") + } + defer func() { + if retErr != nil { + err := ignoreTerminateErrors(p.terminate()) + if err != nil { + logrus.WithError(err).Warn("unable to terminate setnsProcess") + } + } + }() + if p.bootstrapData != nil { + if _, err := io.Copy(p.messageSockPair.parent, p.bootstrapData); err != nil { + return newSystemErrorWithCause(err, "copying bootstrap data to pipe") + } + } + if err := p.execSetns(); err != nil { + return newSystemErrorWithCause(err, "executing setns process") + } + if len(p.cgroupPaths) > 0 { + if err := cgroups.EnterPid(p.cgroupPaths, p.pid()); err != nil && !p.rootlessCgroups { + // On cgroup v2 + nesting + domain controllers, EnterPid may fail with EBUSY. + // https://github.com/opencontainers/runc/issues/2356#issuecomment-621277643 + // Try to join the cgroup of InitProcessPid. + if cgroups.IsCgroup2UnifiedMode() { + initProcCgroupFile := fmt.Sprintf("/proc/%d/cgroup", p.initProcessPid) + initCg, initCgErr := cgroups.ParseCgroupFile(initProcCgroupFile) + if initCgErr == nil { + if initCgPath, ok := initCg[""]; ok { + initCgDirpath := filepath.Join(fs2.UnifiedMountpoint, initCgPath) + logrus.Debugf("adding pid %d to cgroups %v failed (%v), attempting to join %q (obtained from %s)", + p.pid(), p.cgroupPaths, err, initCg, initCgDirpath) + // NOTE: initCgDirPath is not guaranteed to exist because we didn't pause the container. + err = cgroups.WriteCgroupProc(initCgDirpath, p.pid()) + } + } + } + if err != nil { + return newSystemErrorWithCausef(err, "adding pid %d to cgroups", p.pid()) + } + } + } + if p.intelRdtPath != "" { + // if Intel RDT "resource control" filesystem path exists + _, err := os.Stat(p.intelRdtPath) + if err == nil { + if err := intelrdt.WriteIntelRdtTasks(p.intelRdtPath, p.pid()); err != nil { + return newSystemErrorWithCausef(err, "adding pid %d to Intel RDT resource control filesystem", p.pid()) + } + } + } + // set rlimits, this has to be done here because we lose permissions + // to raise the limits once we enter a user-namespace + if err := setupRlimits(p.config.Rlimits, p.pid()); err != nil { + return newSystemErrorWithCause(err, "setting rlimits for process") + } + if err := utils.WriteJSON(p.messageSockPair.parent, p.config); err != nil { + return newSystemErrorWithCause(err, "writing config to pipe") + } + + ierr := parseSync(p.messageSockPair.parent, func(sync *syncT) error { + switch sync.Type { + case procReady: + // This shouldn't happen. + panic("unexpected procReady in setns") + case procHooks: + // This shouldn't happen. + panic("unexpected procHooks in setns") + default: + return newSystemError(errors.New("invalid JSON payload from child")) + } + }) + + if err := unix.Shutdown(int(p.messageSockPair.parent.Fd()), unix.SHUT_WR); err != nil { + return newSystemErrorWithCause(err, "calling shutdown on init pipe") + } + // Must be done after Shutdown so the child will exit and we can wait for it. + if ierr != nil { + p.wait() + return ierr + } + return nil +} + +// execSetns runs the process that executes C code to perform the setns calls +// because setns support requires the C process to fork off a child and perform the setns +// before the go runtime boots, we wait on the process to die and receive the child's pid +// over the provided pipe. +func (p *setnsProcess) execSetns() error { + status, err := p.cmd.Process.Wait() + if err != nil { + p.cmd.Wait() + return newSystemErrorWithCause(err, "waiting on setns process to finish") + } + if !status.Success() { + p.cmd.Wait() + return newSystemError(&exec.ExitError{ProcessState: status}) + } + var pid *pid + if err := json.NewDecoder(p.messageSockPair.parent).Decode(&pid); err != nil { + p.cmd.Wait() + return newSystemErrorWithCause(err, "reading pid from init pipe") + } + + // Clean up the zombie parent process + // On Unix systems FindProcess always succeeds. + firstChildProcess, _ := os.FindProcess(pid.PidFirstChild) + + // Ignore the error in case the child has already been reaped for any reason + _, _ = firstChildProcess.Wait() + + process, err := os.FindProcess(pid.Pid) + if err != nil { + return err + } + p.cmd.Process = process + p.process.ops = p + return nil +} + +// terminate sends a SIGKILL to the forked process for the setns routine then waits to +// avoid the process becoming a zombie. +func (p *setnsProcess) terminate() error { + if p.cmd.Process == nil { + return nil + } + err := p.cmd.Process.Kill() + if _, werr := p.wait(); err == nil { + err = werr + } + return err +} + +func (p *setnsProcess) wait() (*os.ProcessState, error) { + err := p.cmd.Wait() + + // Return actual ProcessState even on Wait error + return p.cmd.ProcessState, err +} + +func (p *setnsProcess) pid() int { + return p.cmd.Process.Pid +} + +func (p *setnsProcess) externalDescriptors() []string { + return p.fds +} + +func (p *setnsProcess) setExternalDescriptors(newFds []string) { + p.fds = newFds +} + +func (p *setnsProcess) forwardChildLogs() { + go logs.ForwardLogs(p.logFilePair.parent) +} + +type initProcess struct { + cmd *exec.Cmd + messageSockPair filePair + logFilePair filePair + config *initConfig + manager cgroups.Manager + intelRdtManager intelrdt.Manager + container *linuxContainer + fds []string + process *Process + bootstrapData io.Reader + sharePidns bool +} + +func (p *initProcess) pid() int { + return p.cmd.Process.Pid +} + +func (p *initProcess) externalDescriptors() []string { + return p.fds +} + +// getChildPid receives the final child's pid over the provided pipe. +func (p *initProcess) getChildPid() (int, error) { + var pid pid + if err := json.NewDecoder(p.messageSockPair.parent).Decode(&pid); err != nil { + p.cmd.Wait() + return -1, err + } + + // Clean up the zombie parent process + // On Unix systems FindProcess always succeeds. + firstChildProcess, _ := os.FindProcess(pid.PidFirstChild) + + // Ignore the error in case the child has already been reaped for any reason + _, _ = firstChildProcess.Wait() + + return pid.Pid, nil +} + +func (p *initProcess) waitForChildExit(childPid int) error { + status, err := p.cmd.Process.Wait() + if err != nil { + p.cmd.Wait() + return err + } + if !status.Success() { + p.cmd.Wait() + return &exec.ExitError{ProcessState: status} + } + + process, err := os.FindProcess(childPid) + if err != nil { + return err + } + p.cmd.Process = process + p.process.ops = p + return nil +} + +func (p *initProcess) start() (retErr error) { + defer p.messageSockPair.parent.Close() + err := p.cmd.Start() + p.process.ops = p + // close the write-side of the pipes (controlled by child) + p.messageSockPair.child.Close() + p.logFilePair.child.Close() + if err != nil { + p.process.ops = nil + return newSystemErrorWithCause(err, "starting init process command") + } + defer func() { + if retErr != nil { + // terminate the process to ensure we can remove cgroups + if err := ignoreTerminateErrors(p.terminate()); err != nil { + logrus.WithError(err).Warn("unable to terminate initProcess") + } + + p.manager.Destroy() + if p.intelRdtManager != nil { + p.intelRdtManager.Destroy() + } + } + }() + + // Do this before syncing with child so that no children can escape the + // cgroup. We don't need to worry about not doing this and not being root + // because we'd be using the rootless cgroup manager in that case. + if err := p.manager.Apply(p.pid()); err != nil { + return newSystemErrorWithCause(err, "applying cgroup configuration for process") + } + if p.intelRdtManager != nil { + if err := p.intelRdtManager.Apply(p.pid()); err != nil { + return newSystemErrorWithCause(err, "applying Intel RDT configuration for process") + } + } + if _, err := io.Copy(p.messageSockPair.parent, p.bootstrapData); err != nil { + return newSystemErrorWithCause(err, "copying bootstrap data to pipe") + } + childPid, err := p.getChildPid() + if err != nil { + return newSystemErrorWithCause(err, "getting the final child's pid from pipe") + } + + // Save the standard descriptor names before the container process + // can potentially move them (e.g., via dup2()). If we don't do this now, + // we won't know at checkpoint time which file descriptor to look up. + fds, err := getPipeFds(childPid) + if err != nil { + return newSystemErrorWithCausef(err, "getting pipe fds for pid %d", childPid) + } + p.setExternalDescriptors(fds) + + // Now it's time to setup cgroup namesapce + if p.config.Config.Namespaces.Contains(configs.NEWCGROUP) && p.config.Config.Namespaces.PathOf(configs.NEWCGROUP) == "" { + if _, err := p.messageSockPair.parent.Write([]byte{createCgroupns}); err != nil { + return newSystemErrorWithCause(err, "sending synchronization value to init process") + } + } + + // Wait for our first child to exit + if err := p.waitForChildExit(childPid); err != nil { + return newSystemErrorWithCause(err, "waiting for our first child to exit") + } + + if err := p.createNetworkInterfaces(); err != nil { + return newSystemErrorWithCause(err, "creating network interfaces") + } + if err := p.updateSpecState(); err != nil { + return newSystemErrorWithCause(err, "updating the spec state") + } + if err := p.sendConfig(); err != nil { + return newSystemErrorWithCause(err, "sending config to init process") + } + var ( + sentRun bool + sentResume bool + ) + + ierr := parseSync(p.messageSockPair.parent, func(sync *syncT) error { + switch sync.Type { + case procReady: + // set rlimits, this has to be done here because we lose permissions + // to raise the limits once we enter a user-namespace + if err := setupRlimits(p.config.Rlimits, p.pid()); err != nil { + return newSystemErrorWithCause(err, "setting rlimits for ready process") + } + // call prestart and CreateRuntime hooks + if !p.config.Config.Namespaces.Contains(configs.NEWNS) { + // Setup cgroup before the hook, so that the prestart and CreateRuntime hook could apply cgroup permissions. + if err := p.manager.Set(p.config.Config); err != nil { + return newSystemErrorWithCause(err, "setting cgroup config for ready process") + } + if p.intelRdtManager != nil { + if err := p.intelRdtManager.Set(p.config.Config); err != nil { + return newSystemErrorWithCause(err, "setting Intel RDT config for ready process") + } + } + + if p.config.Config.Hooks != nil { + s, err := p.container.currentOCIState() + if err != nil { + return err + } + // initProcessStartTime hasn't been set yet. + s.Pid = p.cmd.Process.Pid + s.Status = specs.StateCreating + hooks := p.config.Config.Hooks + + if err := hooks[configs.Prestart].RunHooks(s); err != nil { + return err + } + if err := hooks[configs.CreateRuntime].RunHooks(s); err != nil { + return err + } + } + } + + // generate a timestamp indicating when the container was started + p.container.created = time.Now().UTC() + p.container.state = &createdState{ + c: p.container, + } + + // NOTE: If the procRun state has been synced and the + // runc-create process has been killed for some reason, + // the runc-init[2:stage] process will be leaky. And + // the runc command also fails to parse root directory + // because the container doesn't have state.json. + // + // In order to cleanup the runc-init[2:stage] by + // runc-delete/stop, we should store the status before + // procRun sync. + state, uerr := p.container.updateState(p) + if uerr != nil { + return newSystemErrorWithCause(err, "store init state") + } + p.container.initProcessStartTime = state.InitProcessStartTime + + // Sync with child. + if err := writeSync(p.messageSockPair.parent, procRun); err != nil { + return newSystemErrorWithCause(err, "writing syncT 'run'") + } + sentRun = true + case procHooks: + // Setup cgroup before prestart hook, so that the prestart hook could apply cgroup permissions. + if err := p.manager.Set(p.config.Config); err != nil { + return newSystemErrorWithCause(err, "setting cgroup config for procHooks process") + } + if p.intelRdtManager != nil { + if err := p.intelRdtManager.Set(p.config.Config); err != nil { + return newSystemErrorWithCause(err, "setting Intel RDT config for procHooks process") + } + } + if p.config.Config.Hooks != nil { + s, err := p.container.currentOCIState() + if err != nil { + return err + } + // initProcessStartTime hasn't been set yet. + s.Pid = p.cmd.Process.Pid + s.Status = specs.StateCreating + hooks := p.config.Config.Hooks + + if err := hooks[configs.Prestart].RunHooks(s); err != nil { + return err + } + if err := hooks[configs.CreateRuntime].RunHooks(s); err != nil { + return err + } + } + // Sync with child. + if err := writeSync(p.messageSockPair.parent, procResume); err != nil { + return newSystemErrorWithCause(err, "writing syncT 'resume'") + } + sentResume = true + default: + return newSystemError(errors.New("invalid JSON payload from child")) + } + + return nil + }) + + if !sentRun { + return newSystemErrorWithCause(ierr, "container init") + } + if p.config.Config.Namespaces.Contains(configs.NEWNS) && !sentResume { + return newSystemError(errors.New("could not synchronise after executing prestart and CreateRuntime hooks with container process")) + } + if err := unix.Shutdown(int(p.messageSockPair.parent.Fd()), unix.SHUT_WR); err != nil { + return newSystemErrorWithCause(err, "shutting down init pipe") + } + + // Must be done after Shutdown so the child will exit and we can wait for it. + if ierr != nil { + p.wait() + return ierr + } + return nil +} + +func (p *initProcess) wait() (*os.ProcessState, error) { + err := p.cmd.Wait() + // we should kill all processes in cgroup when init is died if we use host PID namespace + if p.sharePidns { + signalAllProcesses(p.manager, unix.SIGKILL) + } + return p.cmd.ProcessState, err +} + +func (p *initProcess) terminate() error { + if p.cmd.Process == nil { + return nil + } + err := p.cmd.Process.Kill() + if _, werr := p.wait(); err == nil { + err = werr + } + return err +} + +func (p *initProcess) startTime() (uint64, error) { + stat, err := system.Stat(p.pid()) + return stat.StartTime, err +} + +func (p *initProcess) updateSpecState() error { + s, err := p.container.currentOCIState() + if err != nil { + return err + } + + p.config.SpecState = s + return nil +} + +func (p *initProcess) sendConfig() error { + // send the config to the container's init process, we don't use JSON Encode + // here because there might be a problem in JSON decoder in some cases, see: + // https://github.com/docker/docker/issues/14203#issuecomment-174177790 + return utils.WriteJSON(p.messageSockPair.parent, p.config) +} + +func (p *initProcess) createNetworkInterfaces() error { + for _, config := range p.config.Config.Networks { + strategy, err := getStrategy(config.Type) + if err != nil { + return err + } + n := &network{ + Network: *config, + } + if err := strategy.create(n, p.pid()); err != nil { + return err + } + p.config.Networks = append(p.config.Networks, n) + } + return nil +} + +func (p *initProcess) signal(sig os.Signal) error { + s, ok := sig.(unix.Signal) + if !ok { + return errors.New("os: unsupported signal type") + } + return unix.Kill(p.pid(), s) +} + +func (p *initProcess) setExternalDescriptors(newFds []string) { + p.fds = newFds +} + +func (p *initProcess) forwardChildLogs() { + go logs.ForwardLogs(p.logFilePair.parent) +} + +func getPipeFds(pid int) ([]string, error) { + fds := make([]string, 3) + + dirPath := filepath.Join("/proc", strconv.Itoa(pid), "/fd") + for i := 0; i < 3; i++ { + // XXX: This breaks if the path is not a valid symlink (which can + // happen in certain particularly unlucky mount namespace setups). + f := filepath.Join(dirPath, strconv.Itoa(i)) + target, err := os.Readlink(f) + if err != nil { + // Ignore permission errors, for rootless containers and other + // non-dumpable processes. if we can't get the fd for a particular + // file, there's not much we can do. + if os.IsPermission(err) { + continue + } + return fds, err + } + fds[i] = target + } + return fds, nil +} + +// InitializeIO creates pipes for use with the process's stdio and returns the +// opposite side for each. Do not use this if you want to have a pseudoterminal +// set up for you by libcontainer (TODO: fix that too). +// TODO: This is mostly unnecessary, and should be handled by clients. +func (p *Process) InitializeIO(rootuid, rootgid int) (i *IO, err error) { + var fds []uintptr + i = &IO{} + // cleanup in case of an error + defer func() { + if err != nil { + for _, fd := range fds { + unix.Close(int(fd)) + } + } + }() + // STDIN + r, w, err := os.Pipe() + if err != nil { + return nil, err + } + fds = append(fds, r.Fd(), w.Fd()) + p.Stdin, i.Stdin = r, w + // STDOUT + if r, w, err = os.Pipe(); err != nil { + return nil, err + } + fds = append(fds, r.Fd(), w.Fd()) + p.Stdout, i.Stdout = w, r + // STDERR + if r, w, err = os.Pipe(); err != nil { + return nil, err + } + fds = append(fds, r.Fd(), w.Fd()) + p.Stderr, i.Stderr = w, r + // change ownership of the pipes in case we are in a user namespace + for _, fd := range fds { + if err := unix.Fchown(int(fd), rootuid, rootgid); err != nil { + return nil, err + } + } + return i, nil +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/restored_process.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/restored_process.go new file mode 100644 index 000000000000..f861e82d1b28 --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/restored_process.go @@ -0,0 +1,129 @@ +// +build linux + +package libcontainer + +import ( + "fmt" + "os" + "os/exec" + + "github.com/opencontainers/runc/libcontainer/system" +) + +func newRestoredProcess(cmd *exec.Cmd, fds []string) (*restoredProcess, error) { + var ( + err error + ) + pid := cmd.Process.Pid + stat, err := system.Stat(pid) + if err != nil { + return nil, err + } + return &restoredProcess{ + cmd: cmd, + processStartTime: stat.StartTime, + fds: fds, + }, nil +} + +type restoredProcess struct { + cmd *exec.Cmd + processStartTime uint64 + fds []string +} + +func (p *restoredProcess) start() error { + return newGenericError(fmt.Errorf("restored process cannot be started"), SystemError) +} + +func (p *restoredProcess) pid() int { + return p.cmd.Process.Pid +} + +func (p *restoredProcess) terminate() error { + err := p.cmd.Process.Kill() + if _, werr := p.wait(); err == nil { + err = werr + } + return err +} + +func (p *restoredProcess) wait() (*os.ProcessState, error) { + // TODO: how do we wait on the actual process? + // maybe use --exec-cmd in criu + err := p.cmd.Wait() + if err != nil { + if _, ok := err.(*exec.ExitError); !ok { + return nil, err + } + } + st := p.cmd.ProcessState + return st, nil +} + +func (p *restoredProcess) startTime() (uint64, error) { + return p.processStartTime, nil +} + +func (p *restoredProcess) signal(s os.Signal) error { + return p.cmd.Process.Signal(s) +} + +func (p *restoredProcess) externalDescriptors() []string { + return p.fds +} + +func (p *restoredProcess) setExternalDescriptors(newFds []string) { + p.fds = newFds +} + +func (p *restoredProcess) forwardChildLogs() { +} + +// nonChildProcess represents a process where the calling process is not +// the parent process. This process is created when a factory loads a container from +// a persisted state. +type nonChildProcess struct { + processPid int + processStartTime uint64 + fds []string +} + +func (p *nonChildProcess) start() error { + return newGenericError(fmt.Errorf("restored process cannot be started"), SystemError) +} + +func (p *nonChildProcess) pid() int { + return p.processPid +} + +func (p *nonChildProcess) terminate() error { + return newGenericError(fmt.Errorf("restored process cannot be terminated"), SystemError) +} + +func (p *nonChildProcess) wait() (*os.ProcessState, error) { + return nil, newGenericError(fmt.Errorf("restored process cannot be waited on"), SystemError) +} + +func (p *nonChildProcess) startTime() (uint64, error) { + return p.processStartTime, nil +} + +func (p *nonChildProcess) signal(s os.Signal) error { + proc, err := os.FindProcess(p.processPid) + if err != nil { + return err + } + return proc.Signal(s) +} + +func (p *nonChildProcess) externalDescriptors() []string { + return p.fds +} + +func (p *nonChildProcess) setExternalDescriptors(newFds []string) { + p.fds = newFds +} + +func (p *nonChildProcess) forwardChildLogs() { +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go new file mode 100644 index 000000000000..411496ab7c6d --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go @@ -0,0 +1,1047 @@ +// +build linux + +package libcontainer + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + "path" + "path/filepath" + "strings" + "time" + + securejoin "github.com/cyphar/filepath-securejoin" + "github.com/moby/sys/mountinfo" + "github.com/mrunalp/fileutils" + "github.com/opencontainers/runc/libcontainer/cgroups" + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/devices" + "github.com/opencontainers/runc/libcontainer/system" + "github.com/opencontainers/runc/libcontainer/utils" + libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils" + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/opencontainers/selinux/go-selinux/label" + "golang.org/x/sys/unix" +) + +const defaultMountFlags = unix.MS_NOEXEC | unix.MS_NOSUID | unix.MS_NODEV + +// needsSetupDev returns true if /dev needs to be set up. +func needsSetupDev(config *configs.Config) bool { + for _, m := range config.Mounts { + if m.Device == "bind" && libcontainerUtils.CleanPath(m.Destination) == "/dev" { + return false + } + } + return true +} + +// prepareRootfs sets up the devices, mount points, and filesystems for use +// inside a new mount namespace. It doesn't set anything as ro. You must call +// finalizeRootfs after this function to finish setting up the rootfs. +func prepareRootfs(pipe io.ReadWriter, iConfig *initConfig) (err error) { + config := iConfig.Config + if err := prepareRoot(config); err != nil { + return newSystemErrorWithCause(err, "preparing rootfs") + } + + hasCgroupns := config.Namespaces.Contains(configs.NEWCGROUP) + setupDev := needsSetupDev(config) + for _, m := range config.Mounts { + for _, precmd := range m.PremountCmds { + if err := mountCmd(precmd); err != nil { + return newSystemErrorWithCause(err, "running premount command") + } + } + if err := mountToRootfs(m, config.Rootfs, config.MountLabel, hasCgroupns); err != nil { + return newSystemErrorWithCausef(err, "mounting %q to rootfs at %q", m.Source, m.Destination) + } + + for _, postcmd := range m.PostmountCmds { + if err := mountCmd(postcmd); err != nil { + return newSystemErrorWithCause(err, "running postmount command") + } + } + } + + if setupDev { + if err := createDevices(config); err != nil { + return newSystemErrorWithCause(err, "creating device nodes") + } + if err := setupPtmx(config); err != nil { + return newSystemErrorWithCause(err, "setting up ptmx") + } + if err := setupDevSymlinks(config.Rootfs); err != nil { + return newSystemErrorWithCause(err, "setting up /dev symlinks") + } + } + + // Signal the parent to run the pre-start hooks. + // The hooks are run after the mounts are setup, but before we switch to the new + // root, so that the old root is still available in the hooks for any mount + // manipulations. + // Note that iConfig.Cwd is not guaranteed to exist here. + if err := syncParentHooks(pipe); err != nil { + return err + } + + // The reason these operations are done here rather than in finalizeRootfs + // is because the console-handling code gets quite sticky if we have to set + // up the console before doing the pivot_root(2). This is because the + // Console API has to also work with the ExecIn case, which means that the + // API must be able to deal with being inside as well as outside the + // container. It's just cleaner to do this here (at the expense of the + // operation not being perfectly split). + + if err := unix.Chdir(config.Rootfs); err != nil { + return newSystemErrorWithCausef(err, "changing dir to %q", config.Rootfs) + } + + s := iConfig.SpecState + s.Pid = unix.Getpid() + s.Status = specs.StateCreating + if err := iConfig.Config.Hooks[configs.CreateContainer].RunHooks(s); err != nil { + return err + } + + if config.NoPivotRoot { + err = msMoveRoot(config.Rootfs) + } else if config.Namespaces.Contains(configs.NEWNS) { + err = pivotRoot(config.Rootfs) + } else { + err = chroot() + } + if err != nil { + return newSystemErrorWithCause(err, "jailing process inside rootfs") + } + + if setupDev { + if err := reOpenDevNull(); err != nil { + return newSystemErrorWithCause(err, "reopening /dev/null inside container") + } + } + + if cwd := iConfig.Cwd; cwd != "" { + // Note that spec.Process.Cwd can contain unclean value like "../../../../foo/bar...". + // However, we are safe to call MkDirAll directly because we are in the jail here. + if err := os.MkdirAll(cwd, 0755); err != nil { + return err + } + } + + return nil +} + +// finalizeRootfs sets anything to ro if necessary. You must call +// prepareRootfs first. +func finalizeRootfs(config *configs.Config) (err error) { + // remount dev as ro if specified + for _, m := range config.Mounts { + if libcontainerUtils.CleanPath(m.Destination) == "/dev" { + if m.Flags&unix.MS_RDONLY == unix.MS_RDONLY { + if err := remountReadonly(m); err != nil { + return newSystemErrorWithCausef(err, "remounting %q as readonly", m.Destination) + } + } + break + } + } + + // set rootfs ( / ) as readonly + if config.Readonlyfs { + if err := setReadonly(); err != nil { + return newSystemErrorWithCause(err, "setting rootfs as readonly") + } + } + + if config.Umask != nil { + unix.Umask(int(*config.Umask)) + } else { + unix.Umask(0022) + } + return nil +} + +// /tmp has to be mounted as private to allow MS_MOVE to work in all situations +func prepareTmp(topTmpDir string) (string, error) { + tmpdir, err := ioutil.TempDir(topTmpDir, "runctop") + if err != nil { + return "", err + } + if err := unix.Mount(tmpdir, tmpdir, "bind", unix.MS_BIND, ""); err != nil { + return "", err + } + if err := unix.Mount("", tmpdir, "", uintptr(unix.MS_PRIVATE), ""); err != nil { + return "", err + } + return tmpdir, nil +} + +func cleanupTmp(tmpdir string) error { + unix.Unmount(tmpdir, 0) + return os.RemoveAll(tmpdir) +} + +func mountCmd(cmd configs.Command) error { + command := exec.Command(cmd.Path, cmd.Args[:]...) + command.Env = cmd.Env + command.Dir = cmd.Dir + if out, err := command.CombinedOutput(); err != nil { + return fmt.Errorf("%#v failed: %s: %v", cmd, string(out), err) + } + return nil +} + +func prepareBindMount(m *configs.Mount, rootfs string) error { + stat, err := os.Stat(m.Source) + if err != nil { + // error out if the source of a bind mount does not exist as we will be + // unable to bind anything to it. + return err + } + // ensure that the destination of the bind mount is resolved of symlinks at mount time because + // any previous mounts can invalidate the next mount's destination. + // this can happen when a user specifies mounts within other mounts to cause breakouts or other + // evil stuff to try to escape the container's rootfs. + var dest string + if dest, err = securejoin.SecureJoin(rootfs, m.Destination); err != nil { + return err + } + if err := checkProcMount(rootfs, dest, m.Source); err != nil { + return err + } + // update the mount with the correct dest after symlinks are resolved. + m.Destination = dest + if err := createIfNotExists(dest, stat.IsDir()); err != nil { + return err + } + + return nil +} + +func mountCgroupV1(m *configs.Mount, rootfs, mountLabel string, enableCgroupns bool) error { + binds, err := getCgroupMounts(m) + if err != nil { + return err + } + var merged []string + for _, b := range binds { + ss := filepath.Base(b.Destination) + if strings.Contains(ss, ",") { + merged = append(merged, ss) + } + } + tmpfs := &configs.Mount{ + Source: "tmpfs", + Device: "tmpfs", + Destination: m.Destination, + Flags: defaultMountFlags, + Data: "mode=755", + PropagationFlags: m.PropagationFlags, + } + if err := mountToRootfs(tmpfs, rootfs, mountLabel, enableCgroupns); err != nil { + return err + } + for _, b := range binds { + if enableCgroupns { + subsystemPath := filepath.Join(rootfs, b.Destination) + if err := os.MkdirAll(subsystemPath, 0755); err != nil { + return err + } + flags := defaultMountFlags + if m.Flags&unix.MS_RDONLY != 0 { + flags = flags | unix.MS_RDONLY + } + cgroupmount := &configs.Mount{ + Source: "cgroup", + Device: "cgroup", // this is actually fstype + Destination: subsystemPath, + Flags: flags, + Data: filepath.Base(subsystemPath), + } + if err := mountNewCgroup(cgroupmount); err != nil { + return err + } + } else { + if err := mountToRootfs(b, rootfs, mountLabel, enableCgroupns); err != nil { + return err + } + } + } + for _, mc := range merged { + for _, ss := range strings.Split(mc, ",") { + // symlink(2) is very dumb, it will just shove the path into + // the link and doesn't do any checks or relative path + // conversion. Also, don't error out if the cgroup already exists. + if err := os.Symlink(mc, filepath.Join(rootfs, m.Destination, ss)); err != nil && !os.IsExist(err) { + return err + } + } + } + return nil +} + +func mountCgroupV2(m *configs.Mount, rootfs, mountLabel string, enableCgroupns bool) error { + cgroupPath, err := securejoin.SecureJoin(rootfs, m.Destination) + if err != nil { + return err + } + if err := os.MkdirAll(cgroupPath, 0755); err != nil { + return err + } + if err := unix.Mount(m.Source, cgroupPath, "cgroup2", uintptr(m.Flags), m.Data); err != nil { + // when we are in UserNS but CgroupNS is not unshared, we cannot mount cgroup2 (#2158) + if err == unix.EPERM || err == unix.EBUSY { + return unix.Mount("/sys/fs/cgroup", cgroupPath, "", uintptr(m.Flags)|unix.MS_BIND, "") + } + return err + } + return nil +} + +func mountToRootfs(m *configs.Mount, rootfs, mountLabel string, enableCgroupns bool) error { + var ( + dest = m.Destination + ) + if !strings.HasPrefix(dest, rootfs) { + dest = filepath.Join(rootfs, dest) + } + + switch m.Device { + case "proc", "sysfs": + // If the destination already exists and is not a directory, we bail + // out This is to avoid mounting through a symlink or similar -- which + // has been a "fun" attack scenario in the past. + // TODO: This won't be necessary once we switch to libpathrs and we can + // stop all of these symlink-exchange attacks. + if fi, err := os.Lstat(dest); err != nil { + if !os.IsNotExist(err) { + return err + } + } else if fi.Mode()&os.ModeDir == 0 { + return fmt.Errorf("filesystem %q must be mounted on ordinary directory", m.Device) + } + if err := os.MkdirAll(dest, 0755); err != nil { + return err + } + // Selinux kernels do not support labeling of /proc or /sys + return mountPropagate(m, rootfs, "") + case "mqueue": + if err := os.MkdirAll(dest, 0755); err != nil { + return err + } + if err := mountPropagate(m, rootfs, ""); err != nil { + return err + } + return label.SetFileLabel(dest, mountLabel) + case "tmpfs": + copyUp := m.Extensions&configs.EXT_COPYUP == configs.EXT_COPYUP + tmpDir := "" + // dest might be an absolute symlink, so it needs + // to be resolved under rootfs. + dest, err := securejoin.SecureJoin(rootfs, m.Destination) + if err != nil { + return err + } + m.Destination = dest + stat, err := os.Stat(dest) + if err != nil { + if err := os.MkdirAll(dest, 0755); err != nil { + return err + } + } + if copyUp { + tmpdir, err := prepareTmp("/tmp") + if err != nil { + return newSystemErrorWithCause(err, "tmpcopyup: failed to setup tmpdir") + } + defer cleanupTmp(tmpdir) + tmpDir, err = ioutil.TempDir(tmpdir, "runctmpdir") + if err != nil { + return newSystemErrorWithCause(err, "tmpcopyup: failed to create tmpdir") + } + defer os.RemoveAll(tmpDir) + m.Destination = tmpDir + } + if err := mountPropagate(m, rootfs, mountLabel); err != nil { + return err + } + if copyUp { + if err := fileutils.CopyDirectory(dest, tmpDir); err != nil { + errMsg := fmt.Errorf("tmpcopyup: failed to copy %s to %s: %v", dest, tmpDir, err) + if err1 := unix.Unmount(tmpDir, unix.MNT_DETACH); err1 != nil { + return newSystemErrorWithCausef(err1, "tmpcopyup: %v: failed to unmount", errMsg) + } + return errMsg + } + if err := unix.Mount(tmpDir, dest, "", unix.MS_MOVE, ""); err != nil { + errMsg := fmt.Errorf("tmpcopyup: failed to move mount %s to %s: %v", tmpDir, dest, err) + if err1 := unix.Unmount(tmpDir, unix.MNT_DETACH); err1 != nil { + return newSystemErrorWithCausef(err1, "tmpcopyup: %v: failed to unmount", errMsg) + } + return errMsg + } + } + if stat != nil { + if err = os.Chmod(dest, stat.Mode()); err != nil { + return err + } + } + // Initially mounted rw in mountPropagate, remount to ro if flag set. + if m.Flags&unix.MS_RDONLY != 0 { + if err := remount(m, rootfs); err != nil { + return err + } + } + return nil + case "bind": + if err := prepareBindMount(m, rootfs); err != nil { + return err + } + if err := mountPropagate(m, rootfs, mountLabel); err != nil { + return err + } + // bind mount won't change mount options, we need remount to make mount options effective. + // first check that we have non-default options required before attempting a remount + if m.Flags&^(unix.MS_REC|unix.MS_REMOUNT|unix.MS_BIND) != 0 { + // only remount if unique mount options are set + if err := remount(m, rootfs); err != nil { + return err + } + } + + if m.Relabel != "" { + if err := label.Validate(m.Relabel); err != nil { + return err + } + shared := label.IsShared(m.Relabel) + if err := label.Relabel(m.Source, mountLabel, shared); err != nil { + return err + } + } + case "cgroup": + if cgroups.IsCgroup2UnifiedMode() { + return mountCgroupV2(m, rootfs, mountLabel, enableCgroupns) + } + return mountCgroupV1(m, rootfs, mountLabel, enableCgroupns) + default: + // ensure that the destination of the mount is resolved of symlinks at mount time because + // any previous mounts can invalidate the next mount's destination. + // this can happen when a user specifies mounts within other mounts to cause breakouts or other + // evil stuff to try to escape the container's rootfs. + var err error + if dest, err = securejoin.SecureJoin(rootfs, m.Destination); err != nil { + return err + } + if err := checkProcMount(rootfs, dest, m.Source); err != nil { + return err + } + // update the mount with the correct dest after symlinks are resolved. + m.Destination = dest + if err := os.MkdirAll(dest, 0755); err != nil { + return err + } + return mountPropagate(m, rootfs, mountLabel) + } + return nil +} + +func getCgroupMounts(m *configs.Mount) ([]*configs.Mount, error) { + mounts, err := cgroups.GetCgroupMounts(false) + if err != nil { + return nil, err + } + + cgroupPaths, err := cgroups.ParseCgroupFile("/proc/self/cgroup") + if err != nil { + return nil, err + } + + var binds []*configs.Mount + + for _, mm := range mounts { + dir, err := mm.GetOwnCgroup(cgroupPaths) + if err != nil { + return nil, err + } + relDir, err := filepath.Rel(mm.Root, dir) + if err != nil { + return nil, err + } + binds = append(binds, &configs.Mount{ + Device: "bind", + Source: filepath.Join(mm.Mountpoint, relDir), + Destination: filepath.Join(m.Destination, filepath.Base(mm.Mountpoint)), + Flags: unix.MS_BIND | unix.MS_REC | m.Flags, + PropagationFlags: m.PropagationFlags, + }) + } + + return binds, nil +} + +// checkProcMount checks to ensure that the mount destination is not over the top of /proc. +// dest is required to be an abs path and have any symlinks resolved before calling this function. +// +// if source is nil, don't stat the filesystem. This is used for restore of a checkpoint. +func checkProcMount(rootfs, dest, source string) error { + const procPath = "/proc" + path, err := filepath.Rel(filepath.Join(rootfs, procPath), dest) + if err != nil { + return err + } + // pass if the mount path is located outside of /proc + if strings.HasPrefix(path, "..") { + return nil + } + if path == "." { + // an empty source is pasted on restore + if source == "" { + return nil + } + // only allow a mount on-top of proc if it's source is "proc" + isproc, err := isProc(source) + if err != nil { + return err + } + // pass if the mount is happening on top of /proc and the source of + // the mount is a proc filesystem + if isproc { + return nil + } + return fmt.Errorf("%q cannot be mounted because it is not of type proc", dest) + } + + // Here dest is definitely under /proc. Do not allow those, + // except for a few specific entries emulated by lxcfs. + validProcMounts := []string{ + "/proc/cpuinfo", + "/proc/diskstats", + "/proc/meminfo", + "/proc/stat", + "/proc/swaps", + "/proc/uptime", + "/proc/loadavg", + "/proc/slabinfo", + "/proc/net/dev", + } + for _, valid := range validProcMounts { + path, err := filepath.Rel(filepath.Join(rootfs, valid), dest) + if err != nil { + return err + } + if path == "." { + return nil + } + } + + return fmt.Errorf("%q cannot be mounted because it is inside /proc", dest) +} + +func isProc(path string) (bool, error) { + var s unix.Statfs_t + if err := unix.Statfs(path, &s); err != nil { + return false, err + } + return s.Type == unix.PROC_SUPER_MAGIC, nil +} + +func setupDevSymlinks(rootfs string) error { + var links = [][2]string{ + {"/proc/self/fd", "/dev/fd"}, + {"/proc/self/fd/0", "/dev/stdin"}, + {"/proc/self/fd/1", "/dev/stdout"}, + {"/proc/self/fd/2", "/dev/stderr"}, + } + // kcore support can be toggled with CONFIG_PROC_KCORE; only create a symlink + // in /dev if it exists in /proc. + if _, err := os.Stat("/proc/kcore"); err == nil { + links = append(links, [2]string{"/proc/kcore", "/dev/core"}) + } + for _, link := range links { + var ( + src = link[0] + dst = filepath.Join(rootfs, link[1]) + ) + if err := os.Symlink(src, dst); err != nil && !os.IsExist(err) { + return fmt.Errorf("symlink %s %s %s", src, dst, err) + } + } + return nil +} + +// If stdin, stdout, and/or stderr are pointing to `/dev/null` in the parent's rootfs +// this method will make them point to `/dev/null` in this container's rootfs. This +// needs to be called after we chroot/pivot into the container's rootfs so that any +// symlinks are resolved locally. +func reOpenDevNull() error { + var stat, devNullStat unix.Stat_t + file, err := os.OpenFile("/dev/null", os.O_RDWR, 0) + if err != nil { + return fmt.Errorf("Failed to open /dev/null - %s", err) + } + defer file.Close() + if err := unix.Fstat(int(file.Fd()), &devNullStat); err != nil { + return err + } + for fd := 0; fd < 3; fd++ { + if err := unix.Fstat(fd, &stat); err != nil { + return err + } + if stat.Rdev == devNullStat.Rdev { + // Close and re-open the fd. + if err := unix.Dup3(int(file.Fd()), fd, 0); err != nil { + return err + } + } + } + return nil +} + +// Create the device nodes in the container. +func createDevices(config *configs.Config) error { + useBindMount := system.RunningInUserNS() || config.Namespaces.Contains(configs.NEWUSER) + oldMask := unix.Umask(0000) + for _, node := range config.Devices { + + // The /dev/ptmx device is setup by setupPtmx() + if utils.CleanPath(node.Path) == "/dev/ptmx" { + continue + } + + // containers running in a user namespace are not allowed to mknod + // devices so we can just bind mount it from the host. + if err := createDeviceNode(config.Rootfs, node, useBindMount); err != nil { + unix.Umask(oldMask) + return err + } + } + unix.Umask(oldMask) + return nil +} + +func bindMountDeviceNode(dest string, node *devices.Device) error { + f, err := os.Create(dest) + if err != nil && !os.IsExist(err) { + return err + } + if f != nil { + f.Close() + } + return unix.Mount(node.Path, dest, "bind", unix.MS_BIND, "") +} + +// Creates the device node in the rootfs of the container. +func createDeviceNode(rootfs string, node *devices.Device, bind bool) error { + if node.Path == "" { + // The node only exists for cgroup reasons, ignore it here. + return nil + } + dest := filepath.Join(rootfs, node.Path) + if err := os.MkdirAll(filepath.Dir(dest), 0755); err != nil { + return err + } + if bind { + return bindMountDeviceNode(dest, node) + } + if err := mknodDevice(dest, node); err != nil { + if os.IsExist(err) { + return nil + } else if os.IsPermission(err) { + return bindMountDeviceNode(dest, node) + } + return err + } + return nil +} + +func mknodDevice(dest string, node *devices.Device) error { + fileMode := node.FileMode + switch node.Type { + case devices.BlockDevice: + fileMode |= unix.S_IFBLK + case devices.CharDevice: + fileMode |= unix.S_IFCHR + case devices.FifoDevice: + fileMode |= unix.S_IFIFO + default: + return fmt.Errorf("%c is not a valid device type for device %s", node.Type, node.Path) + } + dev, err := node.Mkdev() + if err != nil { + return err + } + if err := unix.Mknod(dest, uint32(fileMode), int(dev)); err != nil { + return err + } + return unix.Chown(dest, int(node.Uid), int(node.Gid)) +} + +// Get the parent mount point of directory passed in as argument. Also return +// optional fields. +func getParentMount(rootfs string) (string, string, error) { + mi, err := mountinfo.GetMounts(mountinfo.ParentsFilter(rootfs)) + if err != nil { + return "", "", err + } + if len(mi) < 1 { + return "", "", fmt.Errorf("could not find parent mount of %s", rootfs) + } + + // find the longest mount point + var idx, maxlen int + for i := range mi { + if len(mi[i].Mountpoint) > maxlen { + maxlen = len(mi[i].Mountpoint) + idx = i + } + } + return mi[idx].Mountpoint, mi[idx].Optional, nil +} + +// Make parent mount private if it was shared +func rootfsParentMountPrivate(rootfs string) error { + sharedMount := false + + parentMount, optionalOpts, err := getParentMount(rootfs) + if err != nil { + return err + } + + optsSplit := strings.Split(optionalOpts, " ") + for _, opt := range optsSplit { + if strings.HasPrefix(opt, "shared:") { + sharedMount = true + break + } + } + + // Make parent mount PRIVATE if it was shared. It is needed for two + // reasons. First of all pivot_root() will fail if parent mount is + // shared. Secondly when we bind mount rootfs it will propagate to + // parent namespace and we don't want that to happen. + if sharedMount { + return unix.Mount("", parentMount, "", unix.MS_PRIVATE, "") + } + + return nil +} + +func prepareRoot(config *configs.Config) error { + flag := unix.MS_SLAVE | unix.MS_REC + if config.RootPropagation != 0 { + flag = config.RootPropagation + } + if err := unix.Mount("", "/", "", uintptr(flag), ""); err != nil { + return err + } + + // Make parent mount private to make sure following bind mount does + // not propagate in other namespaces. Also it will help with kernel + // check pass in pivot_root. (IS_SHARED(new_mnt->mnt_parent)) + if err := rootfsParentMountPrivate(config.Rootfs); err != nil { + return err + } + + return unix.Mount(config.Rootfs, config.Rootfs, "bind", unix.MS_BIND|unix.MS_REC, "") +} + +func setReadonly() error { + flags := uintptr(unix.MS_BIND | unix.MS_REMOUNT | unix.MS_RDONLY) + + err := unix.Mount("", "/", "", flags, "") + if err == nil { + return nil + } + var s unix.Statfs_t + if err := unix.Statfs("/", &s); err != nil { + return &os.PathError{Op: "statfs", Path: "/", Err: err} + } + flags |= uintptr(s.Flags) + return unix.Mount("", "/", "", flags, "") + +} + +func setupPtmx(config *configs.Config) error { + ptmx := filepath.Join(config.Rootfs, "dev/ptmx") + if err := os.Remove(ptmx); err != nil && !os.IsNotExist(err) { + return err + } + if err := os.Symlink("pts/ptmx", ptmx); err != nil { + return fmt.Errorf("symlink dev ptmx %s", err) + } + return nil +} + +// pivotRoot will call pivot_root such that rootfs becomes the new root +// filesystem, and everything else is cleaned up. +func pivotRoot(rootfs string) error { + // While the documentation may claim otherwise, pivot_root(".", ".") is + // actually valid. What this results in is / being the new root but + // /proc/self/cwd being the old root. Since we can play around with the cwd + // with pivot_root this allows us to pivot without creating directories in + // the rootfs. Shout-outs to the LXC developers for giving us this idea. + + oldroot, err := unix.Open("/", unix.O_DIRECTORY|unix.O_RDONLY, 0) + if err != nil { + return err + } + defer unix.Close(oldroot) + + newroot, err := unix.Open(rootfs, unix.O_DIRECTORY|unix.O_RDONLY, 0) + if err != nil { + return err + } + defer unix.Close(newroot) + + // Change to the new root so that the pivot_root actually acts on it. + if err := unix.Fchdir(newroot); err != nil { + return err + } + + if err := unix.PivotRoot(".", "."); err != nil { + return fmt.Errorf("pivot_root %s", err) + } + + // Currently our "." is oldroot (according to the current kernel code). + // However, purely for safety, we will fchdir(oldroot) since there isn't + // really any guarantee from the kernel what /proc/self/cwd will be after a + // pivot_root(2). + + if err := unix.Fchdir(oldroot); err != nil { + return err + } + + // Make oldroot rslave to make sure our unmounts don't propagate to the + // host (and thus bork the machine). We don't use rprivate because this is + // known to cause issues due to races where we still have a reference to a + // mount while a process in the host namespace are trying to operate on + // something they think has no mounts (devicemapper in particular). + if err := unix.Mount("", ".", "", unix.MS_SLAVE|unix.MS_REC, ""); err != nil { + return err + } + // Preform the unmount. MNT_DETACH allows us to unmount /proc/self/cwd. + if err := unix.Unmount(".", unix.MNT_DETACH); err != nil { + return err + } + + // Switch back to our shiny new root. + if err := unix.Chdir("/"); err != nil { + return fmt.Errorf("chdir / %s", err) + } + return nil +} + +func msMoveRoot(rootfs string) error { + // Before we move the root and chroot we have to mask all "full" sysfs and + // procfs mounts which exist on the host. This is because while the kernel + // has protections against mounting procfs if it has masks, when using + // chroot(2) the *host* procfs mount is still reachable in the mount + // namespace and the kernel permits procfs mounts inside --no-pivot + // containers. + // + // Users shouldn't be using --no-pivot except in exceptional circumstances, + // but to avoid such a trivial security flaw we apply a best-effort + // protection here. The kernel only allows a mount of a pseudo-filesystem + // like procfs or sysfs if there is a *full* mount (the root of the + // filesystem is mounted) without any other locked mount points covering a + // subtree of the mount. + // + // So we try to unmount (or mount tmpfs on top of) any mountpoint which is + // a full mount of either sysfs or procfs (since those are the most + // concerning filesystems to us). + mountinfos, err := mountinfo.GetMounts(func(info *mountinfo.Info) (skip, stop bool) { + // Collect every sysfs and procfs filesystem, except for those which + // are non-full mounts or are inside the rootfs of the container. + if info.Root != "/" || + (info.FSType != "proc" && info.FSType != "sysfs") || + strings.HasPrefix(info.Mountpoint, rootfs) { + skip = true + } + return + }) + if err != nil { + return err + } + for _, info := range mountinfos { + p := info.Mountpoint + // Be sure umount events are not propagated to the host. + if err := unix.Mount("", p, "", unix.MS_SLAVE|unix.MS_REC, ""); err != nil { + if err == unix.ENOENT { + // If the mountpoint doesn't exist that means that we've + // already blasted away some parent directory of the mountpoint + // and so we don't care about this error. + continue + } + return err + } + if err := unix.Unmount(p, unix.MNT_DETACH); err != nil { + if err != unix.EINVAL && err != unix.EPERM { + return err + } else { + // If we have not privileges for umounting (e.g. rootless), then + // cover the path. + if err := unix.Mount("tmpfs", p, "tmpfs", 0, ""); err != nil { + return err + } + } + } + } + + // Move the rootfs on top of "/" in our mount namespace. + if err := unix.Mount(rootfs, "/", "", unix.MS_MOVE, ""); err != nil { + return err + } + return chroot() +} + +func chroot() error { + if err := unix.Chroot("."); err != nil { + return err + } + return unix.Chdir("/") +} + +// createIfNotExists creates a file or a directory only if it does not already exist. +func createIfNotExists(path string, isDir bool) error { + if _, err := os.Stat(path); err != nil { + if os.IsNotExist(err) { + if isDir { + return os.MkdirAll(path, 0755) + } + if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { + return err + } + f, err := os.OpenFile(path, os.O_CREATE, 0755) + if err != nil { + return err + } + f.Close() + } + } + return nil +} + +// readonlyPath will make a path read only. +func readonlyPath(path string) error { + if err := unix.Mount(path, path, "", unix.MS_BIND|unix.MS_REC, ""); err != nil { + if os.IsNotExist(err) { + return nil + } + return err + } + return unix.Mount(path, path, "", unix.MS_BIND|unix.MS_REMOUNT|unix.MS_RDONLY|unix.MS_REC, "") +} + +// remountReadonly will remount an existing mount point and ensure that it is read-only. +func remountReadonly(m *configs.Mount) error { + var ( + dest = m.Destination + flags = m.Flags + ) + for i := 0; i < 5; i++ { + // There is a special case in the kernel for + // MS_REMOUNT | MS_BIND, which allows us to change only the + // flags even as an unprivileged user (i.e. user namespace) + // assuming we don't drop any security related flags (nodev, + // nosuid, etc.). So, let's use that case so that we can do + // this re-mount without failing in a userns. + flags |= unix.MS_REMOUNT | unix.MS_BIND | unix.MS_RDONLY + if err := unix.Mount("", dest, "", uintptr(flags), ""); err != nil { + switch err { + case unix.EBUSY: + time.Sleep(100 * time.Millisecond) + continue + default: + return err + } + } + return nil + } + return fmt.Errorf("unable to mount %s as readonly max retries reached", dest) +} + +// maskPath masks the top of the specified path inside a container to avoid +// security issues from processes reading information from non-namespace aware +// mounts ( proc/kcore ). +// For files, maskPath bind mounts /dev/null over the top of the specified path. +// For directories, maskPath mounts read-only tmpfs over the top of the specified path. +func maskPath(path string, mountLabel string) error { + if err := unix.Mount("/dev/null", path, "", unix.MS_BIND, ""); err != nil && !os.IsNotExist(err) { + if err == unix.ENOTDIR { + return unix.Mount("tmpfs", path, "tmpfs", unix.MS_RDONLY, label.FormatMountLabel("", mountLabel)) + } + return err + } + return nil +} + +// writeSystemProperty writes the value to a path under /proc/sys as determined from the key. +// For e.g. net.ipv4.ip_forward translated to /proc/sys/net/ipv4/ip_forward. +func writeSystemProperty(key, value string) error { + keyPath := strings.Replace(key, ".", "/", -1) + return ioutil.WriteFile(path.Join("/proc/sys", keyPath), []byte(value), 0644) +} + +func remount(m *configs.Mount, rootfs string) error { + var ( + dest = m.Destination + ) + if !strings.HasPrefix(dest, rootfs) { + dest = filepath.Join(rootfs, dest) + } + return unix.Mount(m.Source, dest, m.Device, uintptr(m.Flags|unix.MS_REMOUNT), "") +} + +// Do the mount operation followed by additional mounts required to take care +// of propagation flags. +func mountPropagate(m *configs.Mount, rootfs string, mountLabel string) error { + var ( + dest = m.Destination + data = label.FormatMountLabel(m.Data, mountLabel) + flags = m.Flags + ) + if libcontainerUtils.CleanPath(dest) == "/dev" { + flags &= ^unix.MS_RDONLY + } + + // Mount it rw to allow chmod operation. A remount will be performed + // later to make it ro if set. + if m.Device == "tmpfs" { + flags &= ^unix.MS_RDONLY + } + + copyUp := m.Extensions&configs.EXT_COPYUP == configs.EXT_COPYUP + if !(copyUp || strings.HasPrefix(dest, rootfs)) { + dest = filepath.Join(rootfs, dest) + } + + if err := unix.Mount(m.Source, dest, m.Device, uintptr(flags), data); err != nil { + return err + } + + for _, pflag := range m.PropagationFlags { + if err := unix.Mount("", dest, "", uintptr(pflag), ""); err != nil { + return err + } + } + return nil +} + +func mountNewCgroup(m *configs.Mount) error { + var ( + data = m.Data + source = m.Source + ) + if data == "systemd" { + data = cgroups.CgroupNamePrefix + data + source = "systemd" + } + if err := unix.Mount(source, m.Destination, m.Device, uintptr(m.Flags), data); err != nil { + return err + } + return nil +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/setns_init_linux.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/setns_init_linux.go new file mode 100644 index 000000000000..6b1e9a6e97c8 --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/setns_init_linux.go @@ -0,0 +1,90 @@ +// +build linux + +package libcontainer + +import ( + "os" + "runtime" + + "github.com/opencontainers/runc/libcontainer/apparmor" + "github.com/opencontainers/runc/libcontainer/keys" + "github.com/opencontainers/runc/libcontainer/seccomp" + "github.com/opencontainers/runc/libcontainer/system" + "github.com/opencontainers/selinux/go-selinux" + "github.com/pkg/errors" + "golang.org/x/sys/unix" +) + +// linuxSetnsInit performs the container's initialization for running a new process +// inside an existing container. +type linuxSetnsInit struct { + pipe *os.File + consoleSocket *os.File + config *initConfig +} + +func (l *linuxSetnsInit) getSessionRingName() string { + return "_ses." + l.config.ContainerId +} + +func (l *linuxSetnsInit) Init() error { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + if !l.config.Config.NoNewKeyring { + if err := selinux.SetKeyLabel(l.config.ProcessLabel); err != nil { + return err + } + defer selinux.SetKeyLabel("") + // Do not inherit the parent's session keyring. + if _, err := keys.JoinSessionKeyring(l.getSessionRingName()); err != nil { + // Same justification as in standart_init_linux.go as to why we + // don't bail on ENOSYS. + // + // TODO(cyphar): And we should have logging here too. + if errors.Cause(err) != unix.ENOSYS { + return errors.Wrap(err, "join session keyring") + } + } + } + if l.config.CreateConsole { + if err := setupConsole(l.consoleSocket, l.config, false); err != nil { + return err + } + if err := system.Setctty(); err != nil { + return err + } + } + if l.config.NoNewPrivileges { + if err := unix.Prctl(unix.PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); err != nil { + return err + } + } + if err := selinux.SetExecLabel(l.config.ProcessLabel); err != nil { + return err + } + defer selinux.SetExecLabel("") + // Without NoNewPrivileges seccomp is a privileged operation, so we need to + // do this before dropping capabilities; otherwise do it as late as possible + // just before execve so as few syscalls take place after it as possible. + if l.config.Config.Seccomp != nil && !l.config.NoNewPrivileges { + if err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil { + return err + } + } + if err := finalizeNamespace(l.config); err != nil { + return err + } + if err := apparmor.ApplyProfile(l.config.AppArmorProfile); err != nil { + return err + } + // Set seccomp as close to execve as possible, so as few syscalls take + // place afterward (reducing the amount of syscalls that users need to + // enable in their seccomp profiles). + if l.config.Config.Seccomp != nil && l.config.NoNewPrivileges { + if err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil { + return newSystemErrorWithCause(err, "init seccomp") + } + } + return system.Execv(l.config.Args[0], l.config.Args[0:], os.Environ()) +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/capture.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/capture.go new file mode 100644 index 000000000000..0bbe14950409 --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/capture.go @@ -0,0 +1,27 @@ +package stacktrace + +import "runtime" + +// Capture captures a stacktrace for the current calling go program +// +// skip is the number of frames to skip +func Capture(userSkip int) Stacktrace { + var ( + skip = userSkip + 1 // add one for our own function + frames []Frame + prevPc uintptr + ) + for i := skip; ; i++ { + pc, file, line, ok := runtime.Caller(i) + //detect if caller is repeated to avoid loop, gccgo + //currently runs into a loop without this check + if !ok || pc == prevPc { + break + } + frames = append(frames, NewFrame(pc, file, line)) + prevPc = pc + } + return Stacktrace{ + Frames: frames, + } +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/frame.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/frame.go new file mode 100644 index 000000000000..0d590d9a542b --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/frame.go @@ -0,0 +1,38 @@ +package stacktrace + +import ( + "path/filepath" + "runtime" + "strings" +) + +// NewFrame returns a new stack frame for the provided information +func NewFrame(pc uintptr, file string, line int) Frame { + fn := runtime.FuncForPC(pc) + if fn == nil { + return Frame{} + } + pack, name := parseFunctionName(fn.Name()) + return Frame{ + Line: line, + File: filepath.Base(file), + Package: pack, + Function: name, + } +} + +func parseFunctionName(name string) (string, string) { + i := strings.LastIndex(name, ".") + if i == -1 { + return "", name + } + return name[:i], name[i+1:] +} + +// Frame contains all the information for a stack frame within a go program +type Frame struct { + File string + Function string + Package string + Line int +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/stacktrace.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/stacktrace.go new file mode 100644 index 000000000000..5e8b58d2d28b --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/stacktrace/stacktrace.go @@ -0,0 +1,5 @@ +package stacktrace + +type Stacktrace struct { + Frames []Frame +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/standard_init_linux.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/standard_init_linux.go new file mode 100644 index 000000000000..7ec506c462ed --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/standard_init_linux.go @@ -0,0 +1,222 @@ +// +build linux + +package libcontainer + +import ( + "os" + "os/exec" + "runtime" + "strconv" + + "github.com/opencontainers/runc/libcontainer/apparmor" + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/keys" + "github.com/opencontainers/runc/libcontainer/seccomp" + "github.com/opencontainers/runc/libcontainer/system" + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/opencontainers/selinux/go-selinux" + "github.com/pkg/errors" + "golang.org/x/sys/unix" +) + +type linuxStandardInit struct { + pipe *os.File + consoleSocket *os.File + parentPid int + fifoFd int + config *initConfig +} + +func (l *linuxStandardInit) getSessionRingParams() (string, uint32, uint32) { + var newperms uint32 + + if l.config.Config.Namespaces.Contains(configs.NEWUSER) { + // With user ns we need 'other' search permissions. + newperms = 0x8 + } else { + // Without user ns we need 'UID' search permissions. + newperms = 0x80000 + } + + // Create a unique per session container name that we can join in setns; + // However, other containers can also join it. + return "_ses." + l.config.ContainerId, 0xffffffff, newperms +} + +func (l *linuxStandardInit) Init() error { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + if !l.config.Config.NoNewKeyring { + if err := selinux.SetKeyLabel(l.config.ProcessLabel); err != nil { + return err + } + defer selinux.SetKeyLabel("") + ringname, keepperms, newperms := l.getSessionRingParams() + + // Do not inherit the parent's session keyring. + if sessKeyId, err := keys.JoinSessionKeyring(ringname); err != nil { + // If keyrings aren't supported then it is likely we are on an + // older kernel (or inside an LXC container). While we could bail, + // the security feature we are using here is best-effort (it only + // really provides marginal protection since VFS credentials are + // the only significant protection of keyrings). + // + // TODO(cyphar): Log this so people know what's going on, once we + // have proper logging in 'runc init'. + if errors.Cause(err) != unix.ENOSYS { + return errors.Wrap(err, "join session keyring") + } + } else { + // Make session keyring searcheable. If we've gotten this far we + // bail on any error -- we don't want to have a keyring with bad + // permissions. + if err := keys.ModKeyringPerm(sessKeyId, keepperms, newperms); err != nil { + return errors.Wrap(err, "mod keyring permissions") + } + } + } + + if err := setupNetwork(l.config); err != nil { + return err + } + if err := setupRoute(l.config.Config); err != nil { + return err + } + + // initialises the labeling system + selinux.GetEnabled() + if err := prepareRootfs(l.pipe, l.config); err != nil { + return err + } + // Set up the console. This has to be done *before* we finalize the rootfs, + // but *after* we've given the user the chance to set up all of the mounts + // they wanted. + if l.config.CreateConsole { + if err := setupConsole(l.consoleSocket, l.config, true); err != nil { + return err + } + if err := system.Setctty(); err != nil { + return errors.Wrap(err, "setctty") + } + } + + // Finish the rootfs setup. + if l.config.Config.Namespaces.Contains(configs.NEWNS) { + if err := finalizeRootfs(l.config.Config); err != nil { + return err + } + } + + if hostname := l.config.Config.Hostname; hostname != "" { + if err := unix.Sethostname([]byte(hostname)); err != nil { + return errors.Wrap(err, "sethostname") + } + } + if err := apparmor.ApplyProfile(l.config.AppArmorProfile); err != nil { + return errors.Wrap(err, "apply apparmor profile") + } + + for key, value := range l.config.Config.Sysctl { + if err := writeSystemProperty(key, value); err != nil { + return errors.Wrapf(err, "write sysctl key %s", key) + } + } + for _, path := range l.config.Config.ReadonlyPaths { + if err := readonlyPath(path); err != nil { + return errors.Wrapf(err, "readonly path %s", path) + } + } + for _, path := range l.config.Config.MaskPaths { + if err := maskPath(path, l.config.Config.MountLabel); err != nil { + return errors.Wrapf(err, "mask path %s", path) + } + } + pdeath, err := system.GetParentDeathSignal() + if err != nil { + return errors.Wrap(err, "get pdeath signal") + } + if l.config.NoNewPrivileges { + if err := unix.Prctl(unix.PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); err != nil { + return errors.Wrap(err, "set nonewprivileges") + } + } + // Tell our parent that we're ready to Execv. This must be done before the + // Seccomp rules have been applied, because we need to be able to read and + // write to a socket. + if err := syncParentReady(l.pipe); err != nil { + return errors.Wrap(err, "sync ready") + } + if err := selinux.SetExecLabel(l.config.ProcessLabel); err != nil { + return errors.Wrap(err, "set process label") + } + defer selinux.SetExecLabel("") + // Without NoNewPrivileges seccomp is a privileged operation, so we need to + // do this before dropping capabilities; otherwise do it as late as possible + // just before execve so as few syscalls take place after it as possible. + if l.config.Config.Seccomp != nil && !l.config.NoNewPrivileges { + if err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil { + return err + } + } + if err := finalizeNamespace(l.config); err != nil { + return err + } + // finalizeNamespace can change user/group which clears the parent death + // signal, so we restore it here. + if err := pdeath.Restore(); err != nil { + return errors.Wrap(err, "restore pdeath signal") + } + // Compare the parent from the initial start of the init process and make + // sure that it did not change. if the parent changes that means it died + // and we were reparented to something else so we should just kill ourself + // and not cause problems for someone else. + if unix.Getppid() != l.parentPid { + return unix.Kill(unix.Getpid(), unix.SIGKILL) + } + // Check for the arg before waiting to make sure it exists and it is + // returned as a create time error. + name, err := exec.LookPath(l.config.Args[0]) + if err != nil { + return err + } + // Close the pipe to signal that we have completed our init. + l.pipe.Close() + // Wait for the FIFO to be opened on the other side before exec-ing the + // user process. We open it through /proc/self/fd/$fd, because the fd that + // was given to us was an O_PATH fd to the fifo itself. Linux allows us to + // re-open an O_PATH fd through /proc. + fd, err := unix.Open("/proc/self/fd/"+strconv.Itoa(l.fifoFd), unix.O_WRONLY|unix.O_CLOEXEC, 0) + if err != nil { + return newSystemErrorWithCause(err, "open exec fifo") + } + if _, err := unix.Write(fd, []byte("0")); err != nil { + return newSystemErrorWithCause(err, "write 0 exec fifo") + } + // Close the O_PATH fifofd fd before exec because the kernel resets + // dumpable in the wrong order. This has been fixed in newer kernels, but + // we keep this to ensure CVE-2016-9962 doesn't re-emerge on older kernels. + // N.B. the core issue itself (passing dirfds to the host filesystem) has + // since been resolved. + // https://github.com/torvalds/linux/blob/v4.9/fs/exec.c#L1290-L1318 + unix.Close(l.fifoFd) + // Set seccomp as close to execve as possible, so as few syscalls take + // place afterward (reducing the amount of syscalls that users need to + // enable in their seccomp profiles). + if l.config.Config.Seccomp != nil && l.config.NoNewPrivileges { + if err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil { + return newSystemErrorWithCause(err, "init seccomp") + } + } + + s := l.config.SpecState + s.Pid = unix.Getpid() + s.Status = specs.StateCreated + if err := l.config.Config.Hooks[configs.StartContainer].RunHooks(s); err != nil { + return err + } + + if err := unix.Exec(name, l.config.Args[0:], os.Environ()); err != nil { + return newSystemErrorWithCause(err, "exec user process") + } + return nil +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/state_linux.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/state_linux.go new file mode 100644 index 000000000000..02ff06ea9cc2 --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/state_linux.go @@ -0,0 +1,245 @@ +// +build linux + +package libcontainer + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" +) + +func newStateTransitionError(from, to containerState) error { + return &stateTransitionError{ + From: from.status().String(), + To: to.status().String(), + } +} + +// stateTransitionError is returned when an invalid state transition happens from one +// state to another. +type stateTransitionError struct { + From string + To string +} + +func (s *stateTransitionError) Error() string { + return fmt.Sprintf("invalid state transition from %s to %s", s.From, s.To) +} + +type containerState interface { + transition(containerState) error + destroy() error + status() Status +} + +func destroy(c *linuxContainer) error { + if !c.config.Namespaces.Contains(configs.NEWPID) || + c.config.Namespaces.PathOf(configs.NEWPID) != "" { + if err := signalAllProcesses(c.cgroupManager, unix.SIGKILL); err != nil { + logrus.Warn(err) + } + } + err := c.cgroupManager.Destroy() + if c.intelRdtManager != nil { + if ierr := c.intelRdtManager.Destroy(); err == nil { + err = ierr + } + } + if rerr := os.RemoveAll(c.root); err == nil { + err = rerr + } + c.initProcess = nil + if herr := runPoststopHooks(c); err == nil { + err = herr + } + c.state = &stoppedState{c: c} + return err +} + +func runPoststopHooks(c *linuxContainer) error { + hooks := c.config.Hooks + if hooks == nil { + return nil + } + + s, err := c.currentOCIState() + if err != nil { + return err + } + s.Status = specs.StateStopped + + if err := hooks[configs.Poststop].RunHooks(s); err != nil { + return err + } + + return nil +} + +// stoppedState represents a container is a stopped/destroyed state. +type stoppedState struct { + c *linuxContainer +} + +func (b *stoppedState) status() Status { + return Stopped +} + +func (b *stoppedState) transition(s containerState) error { + switch s.(type) { + case *runningState, *restoredState: + b.c.state = s + return nil + case *stoppedState: + return nil + } + return newStateTransitionError(b, s) +} + +func (b *stoppedState) destroy() error { + return destroy(b.c) +} + +// runningState represents a container that is currently running. +type runningState struct { + c *linuxContainer +} + +func (r *runningState) status() Status { + return Running +} + +func (r *runningState) transition(s containerState) error { + switch s.(type) { + case *stoppedState: + if r.c.runType() == Running { + return newGenericError(fmt.Errorf("container still running"), ContainerNotStopped) + } + r.c.state = s + return nil + case *pausedState: + r.c.state = s + return nil + case *runningState: + return nil + } + return newStateTransitionError(r, s) +} + +func (r *runningState) destroy() error { + if r.c.runType() == Running { + return newGenericError(fmt.Errorf("container is not destroyed"), ContainerNotStopped) + } + return destroy(r.c) +} + +type createdState struct { + c *linuxContainer +} + +func (i *createdState) status() Status { + return Created +} + +func (i *createdState) transition(s containerState) error { + switch s.(type) { + case *runningState, *pausedState, *stoppedState: + i.c.state = s + return nil + case *createdState: + return nil + } + return newStateTransitionError(i, s) +} + +func (i *createdState) destroy() error { + i.c.initProcess.signal(unix.SIGKILL) + return destroy(i.c) +} + +// pausedState represents a container that is currently pause. It cannot be destroyed in a +// paused state and must transition back to running first. +type pausedState struct { + c *linuxContainer +} + +func (p *pausedState) status() Status { + return Paused +} + +func (p *pausedState) transition(s containerState) error { + switch s.(type) { + case *runningState, *stoppedState: + p.c.state = s + return nil + case *pausedState: + return nil + } + return newStateTransitionError(p, s) +} + +func (p *pausedState) destroy() error { + t := p.c.runType() + if t != Running && t != Created { + if err := p.c.cgroupManager.Freeze(configs.Thawed); err != nil { + return err + } + return destroy(p.c) + } + return newGenericError(fmt.Errorf("container is paused"), ContainerPaused) +} + +// restoredState is the same as the running state but also has associated checkpoint +// information that maybe need destroyed when the container is stopped and destroy is called. +type restoredState struct { + imageDir string + c *linuxContainer +} + +func (r *restoredState) status() Status { + return Running +} + +func (r *restoredState) transition(s containerState) error { + switch s.(type) { + case *stoppedState, *runningState: + return nil + } + return newStateTransitionError(r, s) +} + +func (r *restoredState) destroy() error { + if _, err := os.Stat(filepath.Join(r.c.root, "checkpoint")); err != nil { + if !os.IsNotExist(err) { + return err + } + } + return destroy(r.c) +} + +// loadedState is used whenever a container is restored, loaded, or setting additional +// processes inside and it should not be destroyed when it is exiting. +type loadedState struct { + c *linuxContainer + s Status +} + +func (n *loadedState) status() Status { + return n.s +} + +func (n *loadedState) transition(s containerState) error { + n.c.state = s + return nil +} + +func (n *loadedState) destroy() error { + if err := n.c.refreshState(); err != nil { + return err + } + return n.c.state.destroy() +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/stats_linux.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/stats_linux.go new file mode 100644 index 000000000000..fff9dd37af3c --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/stats_linux.go @@ -0,0 +1,13 @@ +package libcontainer + +import ( + "github.com/opencontainers/runc/libcontainer/cgroups" + "github.com/opencontainers/runc/libcontainer/intelrdt" + "github.com/opencontainers/runc/types" +) + +type Stats struct { + Interfaces []*types.NetworkInterface + CgroupStats *cgroups.Stats + IntelRdtStats *intelrdt.Stats +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/sync.go b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/sync.go new file mode 100644 index 000000000000..ac88ad22a8ff --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/libcontainer/sync.go @@ -0,0 +1,101 @@ +package libcontainer + +import ( + "encoding/json" + "errors" + "fmt" + "io" + + "github.com/opencontainers/runc/libcontainer/utils" +) + +type syncType string + +// Constants that are used for synchronisation between the parent and child +// during container setup. They come in pairs (with procError being a generic +// response which is followed by a &genericError). +// +// [ child ] <-> [ parent ] +// +// procHooks --> [run hooks] +// <-- procResume +// +// procReady --> [final setup] +// <-- procRun +const ( + procError syncType = "procError" + procReady syncType = "procReady" + procRun syncType = "procRun" + procHooks syncType = "procHooks" + procResume syncType = "procResume" +) + +type syncT struct { + Type syncType `json:"type"` +} + +// writeSync is used to write to a synchronisation pipe. An error is returned +// if there was a problem writing the payload. +func writeSync(pipe io.Writer, sync syncType) error { + return utils.WriteJSON(pipe, syncT{sync}) +} + +// readSync is used to read from a synchronisation pipe. An error is returned +// if we got a genericError, the pipe was closed, or we got an unexpected flag. +func readSync(pipe io.Reader, expected syncType) error { + var procSync syncT + if err := json.NewDecoder(pipe).Decode(&procSync); err != nil { + if err == io.EOF { + return errors.New("parent closed synchronisation channel") + } + return fmt.Errorf("failed reading error from parent: %v", err) + } + + if procSync.Type == procError { + var ierr genericError + + if err := json.NewDecoder(pipe).Decode(&ierr); err != nil { + return fmt.Errorf("failed reading error from parent: %v", err) + } + + return &ierr + } + + if procSync.Type != expected { + return errors.New("invalid synchronisation flag from parent") + } + return nil +} + +// parseSync runs the given callback function on each syncT received from the +// child. It will return once io.EOF is returned from the given pipe. +func parseSync(pipe io.Reader, fn func(*syncT) error) error { + dec := json.NewDecoder(pipe) + for { + var sync syncT + if err := dec.Decode(&sync); err != nil { + if err == io.EOF { + break + } + return err + } + + // We handle this case outside fn for cleanliness reasons. + var ierr *genericError + if sync.Type == procError { + if err := dec.Decode(&ierr); err != nil && err != io.EOF { + return newSystemErrorWithCause(err, "decoding proc error from init") + } + if ierr != nil { + return ierr + } + // Programmer error. + panic("No error following JSON procError payload.") + } + + if err := fn(&sync); err != nil { + return err + } + } + return nil +} diff --git a/src/runtime/vendor/github.com/opencontainers/runc/types/events.go b/src/runtime/vendor/github.com/opencontainers/runc/types/events.go new file mode 100644 index 000000000000..81bde829da59 --- /dev/null +++ b/src/runtime/vendor/github.com/opencontainers/runc/types/events.go @@ -0,0 +1,155 @@ +package types + +import "github.com/opencontainers/runc/libcontainer/intelrdt" + +// Event struct for encoding the event data to json. +type Event struct { + Type string `json:"type"` + ID string `json:"id"` + Data interface{} `json:"data,omitempty"` +} + +// stats is the runc specific stats structure for stability when encoding and decoding stats. +type Stats struct { + CPU Cpu `json:"cpu"` + CPUSet CPUSet `json:"cpuset"` + Memory Memory `json:"memory"` + Pids Pids `json:"pids"` + Blkio Blkio `json:"blkio"` + Hugetlb map[string]Hugetlb `json:"hugetlb"` + IntelRdt IntelRdt `json:"intel_rdt"` + NetworkInterfaces []*NetworkInterface `json:"network_interfaces"` +} + +type Hugetlb struct { + Usage uint64 `json:"usage,omitempty"` + Max uint64 `json:"max,omitempty"` + Failcnt uint64 `json:"failcnt"` +} + +type BlkioEntry struct { + Major uint64 `json:"major,omitempty"` + Minor uint64 `json:"minor,omitempty"` + Op string `json:"op,omitempty"` + Value uint64 `json:"value,omitempty"` +} + +type Blkio struct { + IoServiceBytesRecursive []BlkioEntry `json:"ioServiceBytesRecursive,omitempty"` + IoServicedRecursive []BlkioEntry `json:"ioServicedRecursive,omitempty"` + IoQueuedRecursive []BlkioEntry `json:"ioQueueRecursive,omitempty"` + IoServiceTimeRecursive []BlkioEntry `json:"ioServiceTimeRecursive,omitempty"` + IoWaitTimeRecursive []BlkioEntry `json:"ioWaitTimeRecursive,omitempty"` + IoMergedRecursive []BlkioEntry `json:"ioMergedRecursive,omitempty"` + IoTimeRecursive []BlkioEntry `json:"ioTimeRecursive,omitempty"` + SectorsRecursive []BlkioEntry `json:"sectorsRecursive,omitempty"` +} + +type Pids struct { + Current uint64 `json:"current,omitempty"` + Limit uint64 `json:"limit,omitempty"` +} + +type Throttling struct { + Periods uint64 `json:"periods,omitempty"` + ThrottledPeriods uint64 `json:"throttledPeriods,omitempty"` + ThrottledTime uint64 `json:"throttledTime,omitempty"` +} + +type CpuUsage struct { + // Units: nanoseconds. + Total uint64 `json:"total,omitempty"` + Percpu []uint64 `json:"percpu,omitempty"` + PercpuKernel []uint64 `json:"percpu_kernel,omitempty"` + PercpuUser []uint64 `json:"percpu_user,omitempty"` + Kernel uint64 `json:"kernel"` + User uint64 `json:"user"` +} + +type Cpu struct { + Usage CpuUsage `json:"usage,omitempty"` + Throttling Throttling `json:"throttling,omitempty"` +} + +type CPUSet struct { + CPUs []uint16 `json:"cpus,omitempty"` + CPUExclusive uint64 `json:"cpu_exclusive"` + Mems []uint16 `json:"mems,omitempty"` + MemHardwall uint64 `json:"mem_hardwall"` + MemExclusive uint64 `json:"mem_exclusive"` + MemoryMigrate uint64 `json:"memory_migrate"` + MemorySpreadPage uint64 `json:"memory_spread_page"` + MemorySpreadSlab uint64 `json:"memory_spread_slab"` + MemoryPressure uint64 `json:"memory_pressure"` + SchedLoadBalance uint64 `json:"sched_load_balance"` + SchedRelaxDomainLevel int64 `json:"sched_relax_domain_level"` +} + +type MemoryEntry struct { + Limit uint64 `json:"limit"` + Usage uint64 `json:"usage,omitempty"` + Max uint64 `json:"max,omitempty"` + Failcnt uint64 `json:"failcnt"` +} + +type Memory struct { + Cache uint64 `json:"cache,omitempty"` + Usage MemoryEntry `json:"usage,omitempty"` + Swap MemoryEntry `json:"swap,omitempty"` + Kernel MemoryEntry `json:"kernel,omitempty"` + KernelTCP MemoryEntry `json:"kernelTCP,omitempty"` + Raw map[string]uint64 `json:"raw,omitempty"` +} + +type L3CacheInfo struct { + CbmMask string `json:"cbm_mask,omitempty"` + MinCbmBits uint64 `json:"min_cbm_bits,omitempty"` + NumClosids uint64 `json:"num_closids,omitempty"` +} + +type MemBwInfo struct { + BandwidthGran uint64 `json:"bandwidth_gran,omitempty"` + DelayLinear uint64 `json:"delay_linear,omitempty"` + MinBandwidth uint64 `json:"min_bandwidth,omitempty"` + NumClosids uint64 `json:"num_closids,omitempty"` +} + +type IntelRdt struct { + // The read-only L3 cache information + L3CacheInfo *L3CacheInfo `json:"l3_cache_info,omitempty"` + + // The read-only L3 cache schema in root + L3CacheSchemaRoot string `json:"l3_cache_schema_root,omitempty"` + + // The L3 cache schema in 'container_id' group + L3CacheSchema string `json:"l3_cache_schema,omitempty"` + + // The read-only memory bandwidth information + MemBwInfo *MemBwInfo `json:"mem_bw_info,omitempty"` + + // The read-only memory bandwidth schema in root + MemBwSchemaRoot string `json:"mem_bw_schema_root,omitempty"` + + // The memory bandwidth schema in 'container_id' group + MemBwSchema string `json:"mem_bw_schema,omitempty"` + + // The memory bandwidth monitoring statistics from NUMA nodes in 'container_id' group + MBMStats *[]intelrdt.MBMNumaNodeStats `json:"mbm_stats,omitempty"` + + // The cache monitoring technology statistics from NUMA nodes in 'container_id' group + CMTStats *[]intelrdt.CMTNumaNodeStats `json:"cmt_stats,omitempty"` +} + +type NetworkInterface struct { + // Name is the name of the network interface. + Name string + + RxBytes uint64 + RxPackets uint64 + RxErrors uint64 + RxDropped uint64 + TxBytes uint64 + TxPackets uint64 + TxErrors uint64 + TxDropped uint64 +} diff --git a/src/runtime/vendor/github.com/syndtr/gocapability/LICENSE b/src/runtime/vendor/github.com/syndtr/gocapability/LICENSE new file mode 100644 index 000000000000..80dd96de77fa --- /dev/null +++ b/src/runtime/vendor/github.com/syndtr/gocapability/LICENSE @@ -0,0 +1,24 @@ +Copyright 2013 Suryandaru Triandana +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/runtime/vendor/github.com/syndtr/gocapability/capability/capability.go b/src/runtime/vendor/github.com/syndtr/gocapability/capability/capability.go new file mode 100644 index 000000000000..61a90775e592 --- /dev/null +++ b/src/runtime/vendor/github.com/syndtr/gocapability/capability/capability.go @@ -0,0 +1,133 @@ +// Copyright (c) 2013, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Package capability provides utilities for manipulating POSIX capabilities. +package capability + +type Capabilities interface { + // Get check whether a capability present in the given + // capabilities set. The 'which' value should be one of EFFECTIVE, + // PERMITTED, INHERITABLE, BOUNDING or AMBIENT. + Get(which CapType, what Cap) bool + + // Empty check whether all capability bits of the given capabilities + // set are zero. The 'which' value should be one of EFFECTIVE, + // PERMITTED, INHERITABLE, BOUNDING or AMBIENT. + Empty(which CapType) bool + + // Full check whether all capability bits of the given capabilities + // set are one. The 'which' value should be one of EFFECTIVE, + // PERMITTED, INHERITABLE, BOUNDING or AMBIENT. + Full(which CapType) bool + + // Set sets capabilities of the given capabilities sets. The + // 'which' value should be one or combination (OR'ed) of EFFECTIVE, + // PERMITTED, INHERITABLE, BOUNDING or AMBIENT. + Set(which CapType, caps ...Cap) + + // Unset unsets capabilities of the given capabilities sets. The + // 'which' value should be one or combination (OR'ed) of EFFECTIVE, + // PERMITTED, INHERITABLE, BOUNDING or AMBIENT. + Unset(which CapType, caps ...Cap) + + // Fill sets all bits of the given capabilities kind to one. The + // 'kind' value should be one or combination (OR'ed) of CAPS, + // BOUNDS or AMBS. + Fill(kind CapType) + + // Clear sets all bits of the given capabilities kind to zero. The + // 'kind' value should be one or combination (OR'ed) of CAPS, + // BOUNDS or AMBS. + Clear(kind CapType) + + // String return current capabilities state of the given capabilities + // set as string. The 'which' value should be one of EFFECTIVE, + // PERMITTED, INHERITABLE BOUNDING or AMBIENT + StringCap(which CapType) string + + // String return current capabilities state as string. + String() string + + // Load load actual capabilities value. This will overwrite all + // outstanding changes. + Load() error + + // Apply apply the capabilities settings, so all changes will take + // effect. + Apply(kind CapType) error +} + +// NewPid initializes a new Capabilities object for given pid when +// it is nonzero, or for the current process if pid is 0. +// +// Deprecated: Replace with NewPid2. For example, replace: +// +// c, err := NewPid(0) +// if err != nil { +// return err +// } +// +// with: +// +// c, err := NewPid2(0) +// if err != nil { +// return err +// } +// err = c.Load() +// if err != nil { +// return err +// } +func NewPid(pid int) (Capabilities, error) { + c, err := newPid(pid) + if err != nil { + return c, err + } + err = c.Load() + return c, err +} + +// NewPid2 initializes a new Capabilities object for given pid when +// it is nonzero, or for the current process if pid is 0. This +// does not load the process's current capabilities; to do that you +// must call Load explicitly. +func NewPid2(pid int) (Capabilities, error) { + return newPid(pid) +} + +// NewFile initializes a new Capabilities object for given file path. +// +// Deprecated: Replace with NewFile2. For example, replace: +// +// c, err := NewFile(path) +// if err != nil { +// return err +// } +// +// with: +// +// c, err := NewFile2(path) +// if err != nil { +// return err +// } +// err = c.Load() +// if err != nil { +// return err +// } +func NewFile(path string) (Capabilities, error) { + c, err := newFile(path) + if err != nil { + return c, err + } + err = c.Load() + return c, err +} + +// NewFile2 creates a new initialized Capabilities object for given +// file path. This does not load the process's current capabilities; +// to do that you must call Load explicitly. +func NewFile2(path string) (Capabilities, error) { + return newFile(path) +} diff --git a/src/runtime/vendor/github.com/syndtr/gocapability/capability/capability_linux.go b/src/runtime/vendor/github.com/syndtr/gocapability/capability/capability_linux.go new file mode 100644 index 000000000000..1567dc810400 --- /dev/null +++ b/src/runtime/vendor/github.com/syndtr/gocapability/capability/capability_linux.go @@ -0,0 +1,642 @@ +// Copyright (c) 2013, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package capability + +import ( + "bufio" + "errors" + "fmt" + "io" + "os" + "strings" + "syscall" +) + +var errUnknownVers = errors.New("unknown capability version") + +const ( + linuxCapVer1 = 0x19980330 + linuxCapVer2 = 0x20071026 + linuxCapVer3 = 0x20080522 +) + +var ( + capVers uint32 + capLastCap Cap +) + +func init() { + var hdr capHeader + capget(&hdr, nil) + capVers = hdr.version + + if initLastCap() == nil { + CAP_LAST_CAP = capLastCap + if capLastCap > 31 { + capUpperMask = (uint32(1) << (uint(capLastCap) - 31)) - 1 + } else { + capUpperMask = 0 + } + } +} + +func initLastCap() error { + if capLastCap != 0 { + return nil + } + + f, err := os.Open("/proc/sys/kernel/cap_last_cap") + if err != nil { + return err + } + defer f.Close() + + var b []byte = make([]byte, 11) + _, err = f.Read(b) + if err != nil { + return err + } + + fmt.Sscanf(string(b), "%d", &capLastCap) + + return nil +} + +func mkStringCap(c Capabilities, which CapType) (ret string) { + for i, first := Cap(0), true; i <= CAP_LAST_CAP; i++ { + if !c.Get(which, i) { + continue + } + if first { + first = false + } else { + ret += ", " + } + ret += i.String() + } + return +} + +func mkString(c Capabilities, max CapType) (ret string) { + ret = "{" + for i := CapType(1); i <= max; i <<= 1 { + ret += " " + i.String() + "=\"" + if c.Empty(i) { + ret += "empty" + } else if c.Full(i) { + ret += "full" + } else { + ret += c.StringCap(i) + } + ret += "\"" + } + ret += " }" + return +} + +func newPid(pid int) (c Capabilities, err error) { + switch capVers { + case linuxCapVer1: + p := new(capsV1) + p.hdr.version = capVers + p.hdr.pid = int32(pid) + c = p + case linuxCapVer2, linuxCapVer3: + p := new(capsV3) + p.hdr.version = capVers + p.hdr.pid = int32(pid) + c = p + default: + err = errUnknownVers + return + } + return +} + +type capsV1 struct { + hdr capHeader + data capData +} + +func (c *capsV1) Get(which CapType, what Cap) bool { + if what > 32 { + return false + } + + switch which { + case EFFECTIVE: + return (1< 32 { + continue + } + + if which&EFFECTIVE != 0 { + c.data.effective |= 1 << uint(what) + } + if which&PERMITTED != 0 { + c.data.permitted |= 1 << uint(what) + } + if which&INHERITABLE != 0 { + c.data.inheritable |= 1 << uint(what) + } + } +} + +func (c *capsV1) Unset(which CapType, caps ...Cap) { + for _, what := range caps { + if what > 32 { + continue + } + + if which&EFFECTIVE != 0 { + c.data.effective &= ^(1 << uint(what)) + } + if which&PERMITTED != 0 { + c.data.permitted &= ^(1 << uint(what)) + } + if which&INHERITABLE != 0 { + c.data.inheritable &= ^(1 << uint(what)) + } + } +} + +func (c *capsV1) Fill(kind CapType) { + if kind&CAPS == CAPS { + c.data.effective = 0x7fffffff + c.data.permitted = 0x7fffffff + c.data.inheritable = 0 + } +} + +func (c *capsV1) Clear(kind CapType) { + if kind&CAPS == CAPS { + c.data.effective = 0 + c.data.permitted = 0 + c.data.inheritable = 0 + } +} + +func (c *capsV1) StringCap(which CapType) (ret string) { + return mkStringCap(c, which) +} + +func (c *capsV1) String() (ret string) { + return mkString(c, BOUNDING) +} + +func (c *capsV1) Load() (err error) { + return capget(&c.hdr, &c.data) +} + +func (c *capsV1) Apply(kind CapType) error { + if kind&CAPS == CAPS { + return capset(&c.hdr, &c.data) + } + return nil +} + +type capsV3 struct { + hdr capHeader + data [2]capData + bounds [2]uint32 + ambient [2]uint32 +} + +func (c *capsV3) Get(which CapType, what Cap) bool { + var i uint + if what > 31 { + i = uint(what) >> 5 + what %= 32 + } + + switch which { + case EFFECTIVE: + return (1< 31 { + i = uint(what) >> 5 + what %= 32 + } + + if which&EFFECTIVE != 0 { + c.data[i].effective |= 1 << uint(what) + } + if which&PERMITTED != 0 { + c.data[i].permitted |= 1 << uint(what) + } + if which&INHERITABLE != 0 { + c.data[i].inheritable |= 1 << uint(what) + } + if which&BOUNDING != 0 { + c.bounds[i] |= 1 << uint(what) + } + if which&AMBIENT != 0 { + c.ambient[i] |= 1 << uint(what) + } + } +} + +func (c *capsV3) Unset(which CapType, caps ...Cap) { + for _, what := range caps { + var i uint + if what > 31 { + i = uint(what) >> 5 + what %= 32 + } + + if which&EFFECTIVE != 0 { + c.data[i].effective &= ^(1 << uint(what)) + } + if which&PERMITTED != 0 { + c.data[i].permitted &= ^(1 << uint(what)) + } + if which&INHERITABLE != 0 { + c.data[i].inheritable &= ^(1 << uint(what)) + } + if which&BOUNDING != 0 { + c.bounds[i] &= ^(1 << uint(what)) + } + if which&AMBIENT != 0 { + c.ambient[i] &= ^(1 << uint(what)) + } + } +} + +func (c *capsV3) Fill(kind CapType) { + if kind&CAPS == CAPS { + c.data[0].effective = 0xffffffff + c.data[0].permitted = 0xffffffff + c.data[0].inheritable = 0 + c.data[1].effective = 0xffffffff + c.data[1].permitted = 0xffffffff + c.data[1].inheritable = 0 + } + + if kind&BOUNDS == BOUNDS { + c.bounds[0] = 0xffffffff + c.bounds[1] = 0xffffffff + } + if kind&AMBS == AMBS { + c.ambient[0] = 0xffffffff + c.ambient[1] = 0xffffffff + } +} + +func (c *capsV3) Clear(kind CapType) { + if kind&CAPS == CAPS { + c.data[0].effective = 0 + c.data[0].permitted = 0 + c.data[0].inheritable = 0 + c.data[1].effective = 0 + c.data[1].permitted = 0 + c.data[1].inheritable = 0 + } + + if kind&BOUNDS == BOUNDS { + c.bounds[0] = 0 + c.bounds[1] = 0 + } + if kind&AMBS == AMBS { + c.ambient[0] = 0 + c.ambient[1] = 0 + } +} + +func (c *capsV3) StringCap(which CapType) (ret string) { + return mkStringCap(c, which) +} + +func (c *capsV3) String() (ret string) { + return mkString(c, BOUNDING) +} + +func (c *capsV3) Load() (err error) { + err = capget(&c.hdr, &c.data[0]) + if err != nil { + return + } + + var status_path string + + if c.hdr.pid == 0 { + status_path = fmt.Sprintf("/proc/self/status") + } else { + status_path = fmt.Sprintf("/proc/%d/status", c.hdr.pid) + } + + f, err := os.Open(status_path) + if err != nil { + return + } + b := bufio.NewReader(f) + for { + line, e := b.ReadString('\n') + if e != nil { + if e != io.EOF { + err = e + } + break + } + if strings.HasPrefix(line, "CapB") { + fmt.Sscanf(line[4:], "nd: %08x%08x", &c.bounds[1], &c.bounds[0]) + continue + } + if strings.HasPrefix(line, "CapA") { + fmt.Sscanf(line[4:], "mb: %08x%08x", &c.ambient[1], &c.ambient[0]) + continue + } + } + f.Close() + + return +} + +func (c *capsV3) Apply(kind CapType) (err error) { + if kind&BOUNDS == BOUNDS { + var data [2]capData + err = capget(&c.hdr, &data[0]) + if err != nil { + return + } + if (1< 31 { + if c.data.version == 1 { + return false + } + i = uint(what) >> 5 + what %= 32 + } + + switch which { + case EFFECTIVE: + return (1< 31 { + if c.data.version == 1 { + continue + } + i = uint(what) >> 5 + what %= 32 + } + + if which&EFFECTIVE != 0 { + c.data.effective[i] |= 1 << uint(what) + } + if which&PERMITTED != 0 { + c.data.data[i].permitted |= 1 << uint(what) + } + if which&INHERITABLE != 0 { + c.data.data[i].inheritable |= 1 << uint(what) + } + } +} + +func (c *capsFile) Unset(which CapType, caps ...Cap) { + for _, what := range caps { + var i uint + if what > 31 { + if c.data.version == 1 { + continue + } + i = uint(what) >> 5 + what %= 32 + } + + if which&EFFECTIVE != 0 { + c.data.effective[i] &= ^(1 << uint(what)) + } + if which&PERMITTED != 0 { + c.data.data[i].permitted &= ^(1 << uint(what)) + } + if which&INHERITABLE != 0 { + c.data.data[i].inheritable &= ^(1 << uint(what)) + } + } +} + +func (c *capsFile) Fill(kind CapType) { + if kind&CAPS == CAPS { + c.data.effective[0] = 0xffffffff + c.data.data[0].permitted = 0xffffffff + c.data.data[0].inheritable = 0 + if c.data.version == 2 { + c.data.effective[1] = 0xffffffff + c.data.data[1].permitted = 0xffffffff + c.data.data[1].inheritable = 0 + } + } +} + +func (c *capsFile) Clear(kind CapType) { + if kind&CAPS == CAPS { + c.data.effective[0] = 0 + c.data.data[0].permitted = 0 + c.data.data[0].inheritable = 0 + if c.data.version == 2 { + c.data.effective[1] = 0 + c.data.data[1].permitted = 0 + c.data.data[1].inheritable = 0 + } + } +} + +func (c *capsFile) StringCap(which CapType) (ret string) { + return mkStringCap(c, which) +} + +func (c *capsFile) String() (ret string) { + return mkString(c, INHERITABLE) +} + +func (c *capsFile) Load() (err error) { + return getVfsCap(c.path, &c.data) +} + +func (c *capsFile) Apply(kind CapType) (err error) { + if kind&CAPS == CAPS { + return setVfsCap(c.path, &c.data) + } + return +} diff --git a/src/runtime/vendor/github.com/syndtr/gocapability/capability/capability_noop.go b/src/runtime/vendor/github.com/syndtr/gocapability/capability/capability_noop.go new file mode 100644 index 000000000000..9bb3070c5ec5 --- /dev/null +++ b/src/runtime/vendor/github.com/syndtr/gocapability/capability/capability_noop.go @@ -0,0 +1,19 @@ +// Copyright (c) 2013, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// +build !linux + +package capability + +import "errors" + +func newPid(pid int) (Capabilities, error) { + return nil, errors.New("not supported") +} + +func newFile(path string) (Capabilities, error) { + return nil, errors.New("not supported") +} diff --git a/src/runtime/vendor/github.com/syndtr/gocapability/capability/enum.go b/src/runtime/vendor/github.com/syndtr/gocapability/capability/enum.go new file mode 100644 index 000000000000..ad10785314de --- /dev/null +++ b/src/runtime/vendor/github.com/syndtr/gocapability/capability/enum.go @@ -0,0 +1,309 @@ +// Copyright (c) 2013, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package capability + +type CapType uint + +func (c CapType) String() string { + switch c { + case EFFECTIVE: + return "effective" + case PERMITTED: + return "permitted" + case INHERITABLE: + return "inheritable" + case BOUNDING: + return "bounding" + case CAPS: + return "caps" + case AMBIENT: + return "ambient" + } + return "unknown" +} + +const ( + EFFECTIVE CapType = 1 << iota + PERMITTED + INHERITABLE + BOUNDING + AMBIENT + + CAPS = EFFECTIVE | PERMITTED | INHERITABLE + BOUNDS = BOUNDING + AMBS = AMBIENT +) + +//go:generate go run enumgen/gen.go +type Cap int + +// POSIX-draft defined capabilities and Linux extensions. +// +// Defined in https://github.com/torvalds/linux/blob/master/include/uapi/linux/capability.h +const ( + // In a system with the [_POSIX_CHOWN_RESTRICTED] option defined, this + // overrides the restriction of changing file ownership and group + // ownership. + CAP_CHOWN = Cap(0) + + // Override all DAC access, including ACL execute access if + // [_POSIX_ACL] is defined. Excluding DAC access covered by + // CAP_LINUX_IMMUTABLE. + CAP_DAC_OVERRIDE = Cap(1) + + // Overrides all DAC restrictions regarding read and search on files + // and directories, including ACL restrictions if [_POSIX_ACL] is + // defined. Excluding DAC access covered by CAP_LINUX_IMMUTABLE. + CAP_DAC_READ_SEARCH = Cap(2) + + // Overrides all restrictions about allowed operations on files, where + // file owner ID must be equal to the user ID, except where CAP_FSETID + // is applicable. It doesn't override MAC and DAC restrictions. + CAP_FOWNER = Cap(3) + + // Overrides the following restrictions that the effective user ID + // shall match the file owner ID when setting the S_ISUID and S_ISGID + // bits on that file; that the effective group ID (or one of the + // supplementary group IDs) shall match the file owner ID when setting + // the S_ISGID bit on that file; that the S_ISUID and S_ISGID bits are + // cleared on successful return from chown(2) (not implemented). + CAP_FSETID = Cap(4) + + // Overrides the restriction that the real or effective user ID of a + // process sending a signal must match the real or effective user ID + // of the process receiving the signal. + CAP_KILL = Cap(5) + + // Allows setgid(2) manipulation + // Allows setgroups(2) + // Allows forged gids on socket credentials passing. + CAP_SETGID = Cap(6) + + // Allows set*uid(2) manipulation (including fsuid). + // Allows forged pids on socket credentials passing. + CAP_SETUID = Cap(7) + + // Linux-specific capabilities + + // Without VFS support for capabilities: + // Transfer any capability in your permitted set to any pid, + // remove any capability in your permitted set from any pid + // With VFS support for capabilities (neither of above, but) + // Add any capability from current's capability bounding set + // to the current process' inheritable set + // Allow taking bits out of capability bounding set + // Allow modification of the securebits for a process + CAP_SETPCAP = Cap(8) + + // Allow modification of S_IMMUTABLE and S_APPEND file attributes + CAP_LINUX_IMMUTABLE = Cap(9) + + // Allows binding to TCP/UDP sockets below 1024 + // Allows binding to ATM VCIs below 32 + CAP_NET_BIND_SERVICE = Cap(10) + + // Allow broadcasting, listen to multicast + CAP_NET_BROADCAST = Cap(11) + + // Allow interface configuration + // Allow administration of IP firewall, masquerading and accounting + // Allow setting debug option on sockets + // Allow modification of routing tables + // Allow setting arbitrary process / process group ownership on + // sockets + // Allow binding to any address for transparent proxying (also via NET_RAW) + // Allow setting TOS (type of service) + // Allow setting promiscuous mode + // Allow clearing driver statistics + // Allow multicasting + // Allow read/write of device-specific registers + // Allow activation of ATM control sockets + CAP_NET_ADMIN = Cap(12) + + // Allow use of RAW sockets + // Allow use of PACKET sockets + // Allow binding to any address for transparent proxying (also via NET_ADMIN) + CAP_NET_RAW = Cap(13) + + // Allow locking of shared memory segments + // Allow mlock and mlockall (which doesn't really have anything to do + // with IPC) + CAP_IPC_LOCK = Cap(14) + + // Override IPC ownership checks + CAP_IPC_OWNER = Cap(15) + + // Insert and remove kernel modules - modify kernel without limit + CAP_SYS_MODULE = Cap(16) + + // Allow ioperm/iopl access + // Allow sending USB messages to any device via /proc/bus/usb + CAP_SYS_RAWIO = Cap(17) + + // Allow use of chroot() + CAP_SYS_CHROOT = Cap(18) + + // Allow ptrace() of any process + CAP_SYS_PTRACE = Cap(19) + + // Allow configuration of process accounting + CAP_SYS_PACCT = Cap(20) + + // Allow configuration of the secure attention key + // Allow administration of the random device + // Allow examination and configuration of disk quotas + // Allow setting the domainname + // Allow setting the hostname + // Allow calling bdflush() + // Allow mount() and umount(), setting up new smb connection + // Allow some autofs root ioctls + // Allow nfsservctl + // Allow VM86_REQUEST_IRQ + // Allow to read/write pci config on alpha + // Allow irix_prctl on mips (setstacksize) + // Allow flushing all cache on m68k (sys_cacheflush) + // Allow removing semaphores + // Used instead of CAP_CHOWN to "chown" IPC message queues, semaphores + // and shared memory + // Allow locking/unlocking of shared memory segment + // Allow turning swap on/off + // Allow forged pids on socket credentials passing + // Allow setting readahead and flushing buffers on block devices + // Allow setting geometry in floppy driver + // Allow turning DMA on/off in xd driver + // Allow administration of md devices (mostly the above, but some + // extra ioctls) + // Allow tuning the ide driver + // Allow access to the nvram device + // Allow administration of apm_bios, serial and bttv (TV) device + // Allow manufacturer commands in isdn CAPI support driver + // Allow reading non-standardized portions of pci configuration space + // Allow DDI debug ioctl on sbpcd driver + // Allow setting up serial ports + // Allow sending raw qic-117 commands + // Allow enabling/disabling tagged queuing on SCSI controllers and sending + // arbitrary SCSI commands + // Allow setting encryption key on loopback filesystem + // Allow setting zone reclaim policy + // Allow everything under CAP_BPF and CAP_PERFMON for backward compatibility + CAP_SYS_ADMIN = Cap(21) + + // Allow use of reboot() + CAP_SYS_BOOT = Cap(22) + + // Allow raising priority and setting priority on other (different + // UID) processes + // Allow use of FIFO and round-robin (realtime) scheduling on own + // processes and setting the scheduling algorithm used by another + // process. + // Allow setting cpu affinity on other processes + CAP_SYS_NICE = Cap(23) + + // Override resource limits. Set resource limits. + // Override quota limits. + // Override reserved space on ext2 filesystem + // Modify data journaling mode on ext3 filesystem (uses journaling + // resources) + // NOTE: ext2 honors fsuid when checking for resource overrides, so + // you can override using fsuid too + // Override size restrictions on IPC message queues + // Allow more than 64hz interrupts from the real-time clock + // Override max number of consoles on console allocation + // Override max number of keymaps + // Control memory reclaim behavior + CAP_SYS_RESOURCE = Cap(24) + + // Allow manipulation of system clock + // Allow irix_stime on mips + // Allow setting the real-time clock + CAP_SYS_TIME = Cap(25) + + // Allow configuration of tty devices + // Allow vhangup() of tty + CAP_SYS_TTY_CONFIG = Cap(26) + + // Allow the privileged aspects of mknod() + CAP_MKNOD = Cap(27) + + // Allow taking of leases on files + CAP_LEASE = Cap(28) + + CAP_AUDIT_WRITE = Cap(29) + CAP_AUDIT_CONTROL = Cap(30) + CAP_SETFCAP = Cap(31) + + // Override MAC access. + // The base kernel enforces no MAC policy. + // An LSM may enforce a MAC policy, and if it does and it chooses + // to implement capability based overrides of that policy, this is + // the capability it should use to do so. + CAP_MAC_OVERRIDE = Cap(32) + + // Allow MAC configuration or state changes. + // The base kernel requires no MAC configuration. + // An LSM may enforce a MAC policy, and if it does and it chooses + // to implement capability based checks on modifications to that + // policy or the data required to maintain it, this is the + // capability it should use to do so. + CAP_MAC_ADMIN = Cap(33) + + // Allow configuring the kernel's syslog (printk behaviour) + CAP_SYSLOG = Cap(34) + + // Allow triggering something that will wake the system + CAP_WAKE_ALARM = Cap(35) + + // Allow preventing system suspends + CAP_BLOCK_SUSPEND = Cap(36) + + // Allow reading the audit log via multicast netlink socket + CAP_AUDIT_READ = Cap(37) + + // Allow system performance and observability privileged operations + // using perf_events, i915_perf and other kernel subsystems + CAP_PERFMON = Cap(38) + + // CAP_BPF allows the following BPF operations: + // - Creating all types of BPF maps + // - Advanced verifier features + // - Indirect variable access + // - Bounded loops + // - BPF to BPF function calls + // - Scalar precision tracking + // - Larger complexity limits + // - Dead code elimination + // - And potentially other features + // - Loading BPF Type Format (BTF) data + // - Retrieve xlated and JITed code of BPF programs + // - Use bpf_spin_lock() helper + // + // CAP_PERFMON relaxes the verifier checks further: + // - BPF progs can use of pointer-to-integer conversions + // - speculation attack hardening measures are bypassed + // - bpf_probe_read to read arbitrary kernel memory is allowed + // - bpf_trace_printk to print kernel memory is allowed + // + // CAP_SYS_ADMIN is required to use bpf_probe_write_user. + // + // CAP_SYS_ADMIN is required to iterate system wide loaded + // programs, maps, links, BTFs and convert their IDs to file descriptors. + // + // CAP_PERFMON and CAP_BPF are required to load tracing programs. + // CAP_NET_ADMIN and CAP_BPF are required to load networking programs. + CAP_BPF = Cap(39) + + // Allow checkpoint/restore related operations. + // Introduced in kernel 5.9 + CAP_CHECKPOINT_RESTORE = Cap(40) +) + +var ( + // Highest valid capability of the running kernel. + CAP_LAST_CAP = Cap(63) + + capUpperMask = ^uint32(0) +) diff --git a/src/runtime/vendor/github.com/syndtr/gocapability/capability/enum_gen.go b/src/runtime/vendor/github.com/syndtr/gocapability/capability/enum_gen.go new file mode 100644 index 000000000000..2ff9bf4d8879 --- /dev/null +++ b/src/runtime/vendor/github.com/syndtr/gocapability/capability/enum_gen.go @@ -0,0 +1,138 @@ +// generated file; DO NOT EDIT - use go generate in directory with source + +package capability + +func (c Cap) String() string { + switch c { + case CAP_CHOWN: + return "chown" + case CAP_DAC_OVERRIDE: + return "dac_override" + case CAP_DAC_READ_SEARCH: + return "dac_read_search" + case CAP_FOWNER: + return "fowner" + case CAP_FSETID: + return "fsetid" + case CAP_KILL: + return "kill" + case CAP_SETGID: + return "setgid" + case CAP_SETUID: + return "setuid" + case CAP_SETPCAP: + return "setpcap" + case CAP_LINUX_IMMUTABLE: + return "linux_immutable" + case CAP_NET_BIND_SERVICE: + return "net_bind_service" + case CAP_NET_BROADCAST: + return "net_broadcast" + case CAP_NET_ADMIN: + return "net_admin" + case CAP_NET_RAW: + return "net_raw" + case CAP_IPC_LOCK: + return "ipc_lock" + case CAP_IPC_OWNER: + return "ipc_owner" + case CAP_SYS_MODULE: + return "sys_module" + case CAP_SYS_RAWIO: + return "sys_rawio" + case CAP_SYS_CHROOT: + return "sys_chroot" + case CAP_SYS_PTRACE: + return "sys_ptrace" + case CAP_SYS_PACCT: + return "sys_pacct" + case CAP_SYS_ADMIN: + return "sys_admin" + case CAP_SYS_BOOT: + return "sys_boot" + case CAP_SYS_NICE: + return "sys_nice" + case CAP_SYS_RESOURCE: + return "sys_resource" + case CAP_SYS_TIME: + return "sys_time" + case CAP_SYS_TTY_CONFIG: + return "sys_tty_config" + case CAP_MKNOD: + return "mknod" + case CAP_LEASE: + return "lease" + case CAP_AUDIT_WRITE: + return "audit_write" + case CAP_AUDIT_CONTROL: + return "audit_control" + case CAP_SETFCAP: + return "setfcap" + case CAP_MAC_OVERRIDE: + return "mac_override" + case CAP_MAC_ADMIN: + return "mac_admin" + case CAP_SYSLOG: + return "syslog" + case CAP_WAKE_ALARM: + return "wake_alarm" + case CAP_BLOCK_SUSPEND: + return "block_suspend" + case CAP_AUDIT_READ: + return "audit_read" + case CAP_PERFMON: + return "perfmon" + case CAP_BPF: + return "bpf" + case CAP_CHECKPOINT_RESTORE: + return "checkpoint_restore" + } + return "unknown" +} + +// List returns list of all supported capabilities +func List() []Cap { + return []Cap{ + CAP_CHOWN, + CAP_DAC_OVERRIDE, + CAP_DAC_READ_SEARCH, + CAP_FOWNER, + CAP_FSETID, + CAP_KILL, + CAP_SETGID, + CAP_SETUID, + CAP_SETPCAP, + CAP_LINUX_IMMUTABLE, + CAP_NET_BIND_SERVICE, + CAP_NET_BROADCAST, + CAP_NET_ADMIN, + CAP_NET_RAW, + CAP_IPC_LOCK, + CAP_IPC_OWNER, + CAP_SYS_MODULE, + CAP_SYS_RAWIO, + CAP_SYS_CHROOT, + CAP_SYS_PTRACE, + CAP_SYS_PACCT, + CAP_SYS_ADMIN, + CAP_SYS_BOOT, + CAP_SYS_NICE, + CAP_SYS_RESOURCE, + CAP_SYS_TIME, + CAP_SYS_TTY_CONFIG, + CAP_MKNOD, + CAP_LEASE, + CAP_AUDIT_WRITE, + CAP_AUDIT_CONTROL, + CAP_SETFCAP, + CAP_MAC_OVERRIDE, + CAP_MAC_ADMIN, + CAP_SYSLOG, + CAP_WAKE_ALARM, + CAP_BLOCK_SUSPEND, + CAP_AUDIT_READ, + CAP_PERFMON, + CAP_BPF, + CAP_CHECKPOINT_RESTORE, + } +} diff --git a/src/runtime/vendor/github.com/syndtr/gocapability/capability/syscall_linux.go b/src/runtime/vendor/github.com/syndtr/gocapability/capability/syscall_linux.go new file mode 100644 index 000000000000..3d2bf6927f37 --- /dev/null +++ b/src/runtime/vendor/github.com/syndtr/gocapability/capability/syscall_linux.go @@ -0,0 +1,154 @@ +// Copyright (c) 2013, Suryandaru Triandana +// All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package capability + +import ( + "syscall" + "unsafe" +) + +type capHeader struct { + version uint32 + pid int32 +} + +type capData struct { + effective uint32 + permitted uint32 + inheritable uint32 +} + +func capget(hdr *capHeader, data *capData) (err error) { + _, _, e1 := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = e1 + } + return +} + +func capset(hdr *capHeader, data *capData) (err error) { + _, _, e1 := syscall.Syscall(syscall.SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0) + if e1 != 0 { + err = e1 + } + return +} + +// not yet in syscall +const ( + pr_CAP_AMBIENT = 47 + pr_CAP_AMBIENT_IS_SET = uintptr(1) + pr_CAP_AMBIENT_RAISE = uintptr(2) + pr_CAP_AMBIENT_LOWER = uintptr(3) + pr_CAP_AMBIENT_CLEAR_ALL = uintptr(4) +) + +func prctl(option int, arg2, arg3, arg4, arg5 uintptr) (err error) { + _, _, e1 := syscall.Syscall6(syscall.SYS_PRCTL, uintptr(option), arg2, arg3, arg4, arg5, 0) + if e1 != 0 { + err = e1 + } + return +} + +const ( + vfsXattrName = "security.capability" + + vfsCapVerMask = 0xff000000 + vfsCapVer1 = 0x01000000 + vfsCapVer2 = 0x02000000 + + vfsCapFlagMask = ^vfsCapVerMask + vfsCapFlageffective = 0x000001 + + vfscapDataSizeV1 = 4 * (1 + 2*1) + vfscapDataSizeV2 = 4 * (1 + 2*2) +) + +type vfscapData struct { + magic uint32 + data [2]struct { + permitted uint32 + inheritable uint32 + } + effective [2]uint32 + version int8 +} + +var ( + _vfsXattrName *byte +) + +func init() { + _vfsXattrName, _ = syscall.BytePtrFromString(vfsXattrName) +} + +func getVfsCap(path string, dest *vfscapData) (err error) { + var _p0 *byte + _p0, err = syscall.BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(dest)), vfscapDataSizeV2, 0, 0) + if e1 != 0 { + if e1 == syscall.ENODATA { + dest.version = 2 + return + } + err = e1 + } + switch dest.magic & vfsCapVerMask { + case vfsCapVer1: + dest.version = 1 + if r0 != vfscapDataSizeV1 { + return syscall.EINVAL + } + dest.data[1].permitted = 0 + dest.data[1].inheritable = 0 + case vfsCapVer2: + dest.version = 2 + if r0 != vfscapDataSizeV2 { + return syscall.EINVAL + } + default: + return syscall.EINVAL + } + if dest.magic&vfsCapFlageffective != 0 { + dest.effective[0] = dest.data[0].permitted | dest.data[0].inheritable + dest.effective[1] = dest.data[1].permitted | dest.data[1].inheritable + } else { + dest.effective[0] = 0 + dest.effective[1] = 0 + } + return +} + +func setVfsCap(path string, data *vfscapData) (err error) { + var _p0 *byte + _p0, err = syscall.BytePtrFromString(path) + if err != nil { + return + } + var size uintptr + if data.version == 1 { + data.magic = vfsCapVer1 + size = vfscapDataSizeV1 + } else if data.version == 2 { + data.magic = vfsCapVer2 + if data.effective[0] != 0 || data.effective[1] != 0 { + data.magic |= vfsCapFlageffective + } + size = vfscapDataSizeV2 + } else { + return syscall.EINVAL + } + _, _, e1 := syscall.Syscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(data)), size, 0, 0) + if e1 != 0 { + err = e1 + } + return +} diff --git a/src/runtime/vendor/modules.txt b/src/runtime/vendor/modules.txt index d62d44cc9bce..98d6ff176c56 100644 --- a/src/runtime/vendor/modules.txt +++ b/src/runtime/vendor/modules.txt @@ -47,6 +47,9 @@ github.com/blang/semver github.com/blang/semver/v4 # github.com/cespare/xxhash/v2 v2.1.1 github.com/cespare/xxhash/v2 +# github.com/checkpoint-restore/go-criu/v4 v4.1.0 +github.com/checkpoint-restore/go-criu/v4 +github.com/checkpoint-restore/go-criu/v4/rpc # github.com/cilium/ebpf v0.4.0 github.com/cilium/ebpf github.com/cilium/ebpf/asm @@ -102,6 +105,7 @@ github.com/containerd/containerd/namespaces github.com/containerd/containerd/oci github.com/containerd/containerd/pkg/cap github.com/containerd/containerd/pkg/dialer +github.com/containerd/containerd/pkg/runtimeoptions/v1 github.com/containerd/containerd/pkg/ttrpcutil github.com/containerd/containerd/pkg/userns github.com/containerd/containerd/platforms @@ -280,6 +284,8 @@ github.com/mitchellh/mapstructure github.com/moby/locker # github.com/moby/sys/mountinfo v0.4.1 github.com/moby/sys/mountinfo +# github.com/mrunalp/fileutils v0.5.0 +github.com/mrunalp/fileutils # github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/go-digest # github.com/opencontainers/image-spec v1.0.1 @@ -289,6 +295,9 @@ github.com/opencontainers/image-spec/specs-go github.com/opencontainers/image-spec/specs-go/v1 # github.com/opencontainers/runc v1.0.0-rc93 ## explicit +github.com/opencontainers/runc/libcontainer +github.com/opencontainers/runc/libcontainer/apparmor +github.com/opencontainers/runc/libcontainer/capabilities github.com/opencontainers/runc/libcontainer/cgroups github.com/opencontainers/runc/libcontainer/cgroups/devices github.com/opencontainers/runc/libcontainer/cgroups/ebpf @@ -298,13 +307,19 @@ github.com/opencontainers/runc/libcontainer/cgroups/fs2 github.com/opencontainers/runc/libcontainer/cgroups/fscommon github.com/opencontainers/runc/libcontainer/cgroups/systemd github.com/opencontainers/runc/libcontainer/configs +github.com/opencontainers/runc/libcontainer/configs/validate github.com/opencontainers/runc/libcontainer/devices +github.com/opencontainers/runc/libcontainer/intelrdt +github.com/opencontainers/runc/libcontainer/keys +github.com/opencontainers/runc/libcontainer/logs github.com/opencontainers/runc/libcontainer/seccomp github.com/opencontainers/runc/libcontainer/seccomp/patchbpf github.com/opencontainers/runc/libcontainer/specconv +github.com/opencontainers/runc/libcontainer/stacktrace github.com/opencontainers/runc/libcontainer/system github.com/opencontainers/runc/libcontainer/user github.com/opencontainers/runc/libcontainer/utils +github.com/opencontainers/runc/types # github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d ## explicit github.com/opencontainers/runtime-spec/specs-go @@ -356,6 +371,8 @@ github.com/sirupsen/logrus/hooks/syslog # github.com/stretchr/testify v1.6.1 ## explicit github.com/stretchr/testify/assert +# github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 +github.com/syndtr/gocapability/capability # github.com/urfave/cli v1.22.2 ## explicit github.com/urfave/cli diff --git a/src/runtime/virtcontainers/cgroups.go b/src/runtime/virtcontainers/cgroups.go index 4459df5c3913..eeaf095da9fc 100644 --- a/src/runtime/virtcontainers/cgroups.go +++ b/src/runtime/virtcontainers/cgroups.go @@ -38,7 +38,7 @@ func V1Constraints() ([]cgroups.Subsystem, error) { return nil, err } subsystems := []cgroups.Subsystem{ - cgroups.NewCputset(root), + cgroups.NewCpuset(root), cgroups.NewCpu(root), cgroups.NewCpuacct(root), } diff --git a/src/runtime/virtcontainers/cgroups_test.go b/src/runtime/virtcontainers/cgroups_test.go index baafdad12558..582e93fc99eb 100644 --- a/src/runtime/virtcontainers/cgroups_test.go +++ b/src/runtime/virtcontainers/cgroups_test.go @@ -14,6 +14,7 @@ import ( "testing" "github.com/containerd/cgroups" + cgroupsstatsv1 "github.com/containerd/cgroups/stats/v1" "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/types" specs "github.com/opencontainers/runtime-spec/specs-go" "github.com/stretchr/testify/assert" @@ -41,8 +42,8 @@ func (m *mockCgroup) MoveTo(cgroups.Cgroup) error { return nil } -func (m *mockCgroup) Stat(...cgroups.ErrorHandler) (*cgroups.Metrics, error) { - return &cgroups.Metrics{}, nil +func (m *mockCgroup) Stat(...cgroups.ErrorHandler) (*cgroupsstatsv1.Metrics, error) { + return &cgroupsstatsv1.Metrics{}, nil } func (m *mockCgroup) Update(resources *specs.LinuxResources) error { @@ -65,6 +66,10 @@ func (m *mockCgroup) OOMEventFD() (uintptr, error) { return 0, nil } +func (m *mockCgroup) RegisterMemoryEvent(event cgroups.MemoryEvent) (uintptr, error) { + return 0, nil +} + func (m *mockCgroup) State() cgroups.State { return "" } diff --git a/src/runtime/virtcontainers/kata_agent.go b/src/runtime/virtcontainers/kata_agent.go index 9f3aae1c0048..693f1bd595e0 100644 --- a/src/runtime/virtcontainers/kata_agent.go +++ b/src/runtime/virtcontainers/kata_agent.go @@ -1075,8 +1075,8 @@ func (k *kataAgent) constraintGRPCSpec(grpcSpec *grpc.Spec, passSeccomp bool) { var tmpNamespaces []grpc.LinuxNamespace for _, ns := range grpcSpec.Linux.Namespaces { switch ns.Type { - case specs.CgroupNamespace: - case specs.NetworkNamespace: + case string(specs.CgroupNamespace): + case string(specs.NetworkNamespace): default: ns.Path = "" tmpNamespaces = append(tmpNamespaces, ns) diff --git a/src/runtime/virtcontainers/kata_agent_test.go b/src/runtime/virtcontainers/kata_agent_test.go index 50235f99cd54..e58589f9cf89 100644 --- a/src/runtime/virtcontainers/kata_agent_test.go +++ b/src/runtime/virtcontainers/kata_agent_test.go @@ -553,11 +553,11 @@ func TestConstraintGRPCSpec(t *testing.T) { Seccomp: &pb.LinuxSeccomp{}, Namespaces: []pb.LinuxNamespace{ { - Type: specs.NetworkNamespace, + Type: string(specs.NetworkNamespace), Path: "/abc/123", }, { - Type: specs.MountNamespace, + Type: string(specs.MountNamespace), Path: "/abc/123", }, }, @@ -689,11 +689,11 @@ func TestHandlePidNamespace(t *testing.T) { Linux: &pb.Linux{ Namespaces: []pb.LinuxNamespace{ { - Type: specs.NetworkNamespace, + Type: string(specs.NetworkNamespace), Path: "/abc/123", }, { - Type: specs.MountNamespace, + Type: string(specs.MountNamespace), Path: "/abc/123", }, }, @@ -714,7 +714,7 @@ func TestHandlePidNamespace(t *testing.T) { } utsNs := pb.LinuxNamespace{ - Type: specs.UTSNamespace, + Type: string(specs.UTSNamespace), Path: "", } diff --git a/src/runtime/virtcontainers/physical_endpoint.go b/src/runtime/virtcontainers/physical_endpoint.go index 8fa3293ce451..96fa10944e59 100644 --- a/src/runtime/virtcontainers/physical_endpoint.go +++ b/src/runtime/virtcontainers/physical_endpoint.go @@ -88,13 +88,13 @@ func (endpoint *PhysicalEndpoint) Attach(ctx context.Context, s *Sandbox) error return err } - c, err := cgroups.DeviceToCgroupDevice(vfioPath) + c, err := cgroups.DeviceToCgroupDeviceRule(vfioPath) if err != nil { return err } d := config.DeviceInfo{ - ContainerPath: c.Path, + ContainerPath: vfioPath, DevType: string(c.Type), Major: c.Major, Minor: c.Minor, diff --git a/src/runtime/virtcontainers/pkg/agent/protocols/grpc/agent.pb.go b/src/runtime/virtcontainers/pkg/agent/protocols/grpc/agent.pb.go index bea5225d2e81..417ed5760298 100644 --- a/src/runtime/virtcontainers/pkg/agent/protocols/grpc/agent.pb.go +++ b/src/runtime/virtcontainers/pkg/agent/protocols/grpc/agent.pb.go @@ -35,7 +35,7 @@ type CreateContainerRequest struct { StringUser *StringUser `protobuf:"bytes,3,opt,name=string_user,json=stringUser,proto3" json:"string_user,omitempty"` Devices []*Device `protobuf:"bytes,4,rep,name=devices,proto3" json:"devices,omitempty"` Storages []*Storage `protobuf:"bytes,5,rep,name=storages,proto3" json:"storages,omitempty"` - OCI *Spec `protobuf:"bytes,6,opt,name=OCI,proto3" json:"OCI,omitempty"` + OCI *Spec `protobuf:"bytes,6,opt,name=OCI,json=oCI,proto3" json:"OCI,omitempty"` // This field is used to indicate if the container needs to join // sandbox shared pid ns or create a new namespace. This field is // meant to override the NEWPID config settings in the OCI spec. @@ -1372,7 +1372,7 @@ func (m *DestroySandboxRequest) XXX_DiscardUnknown() { var xxx_messageInfo_DestroySandboxRequest proto.InternalMessageInfo type Interfaces struct { - Interfaces []*protocols.Interface `protobuf:"bytes,1,rep,name=Interfaces,proto3" json:"Interfaces,omitempty"` + Interfaces []*protocols.Interface `protobuf:"bytes,1,rep,name=Interfaces,json=interfaces,proto3" json:"Interfaces,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1411,7 +1411,7 @@ func (m *Interfaces) XXX_DiscardUnknown() { var xxx_messageInfo_Interfaces proto.InternalMessageInfo type Routes struct { - Routes []*protocols.Route `protobuf:"bytes,1,rep,name=Routes,proto3" json:"Routes,omitempty"` + Routes []*protocols.Route `protobuf:"bytes,1,rep,name=Routes,json=routes,proto3" json:"Routes,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1604,7 +1604,7 @@ func (m *ListRoutesRequest) XXX_DiscardUnknown() { var xxx_messageInfo_ListRoutesRequest proto.InternalMessageInfo type ARPNeighbors struct { - ARPNeighbors []*protocols.ARPNeighbor `protobuf:"bytes,1,rep,name=ARPNeighbors,proto3" json:"ARPNeighbors,omitempty"` + ARPNeighbors []*protocols.ARPNeighbor `protobuf:"bytes,1,rep,name=ARPNeighbors,json=aRPNeighbors,proto3" json:"ARPNeighbors,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1948,9 +1948,9 @@ var xxx_messageInfo_MemHotplugByProbeRequest proto.InternalMessageInfo type SetGuestDateTimeRequest struct { // Sec the second since the Epoch. - Sec int64 `protobuf:"varint,1,opt,name=Sec,proto3" json:"Sec,omitempty"` + Sec int64 `protobuf:"varint,1,opt,name=Sec,json=sec,proto3" json:"Sec,omitempty"` // Usec the microseconds portion of time since the Epoch. - Usec int64 `protobuf:"varint,2,opt,name=Usec,proto3" json:"Usec,omitempty"` + Usec int64 `protobuf:"varint,2,opt,name=Usec,json=usec,proto3" json:"Usec,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -2519,193 +2519,194 @@ func init() { } var fileDescriptor_c1460208c38ccf5e = []byte{ - // 2971 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x1a, 0xcb, 0x72, 0x24, 0x47, - 0xd1, 0xf3, 0x90, 0x66, 0x26, 0xe7, 0xa5, 0x69, 0x69, 0xb5, 0xb3, 0x63, 0x5b, 0xac, 0x7b, 0xed, - 0xb5, 0x8c, 0xf1, 0xc8, 0x5e, 0x3b, 0x58, 0x3f, 0xc2, 0x6c, 0xac, 0x1e, 0x96, 0x64, 0x5b, 0x96, - 0xdc, 0x5a, 0x85, 0x09, 0x08, 0xe8, 0x68, 0x75, 0x97, 0x66, 0xca, 0x9a, 0xee, 0x6a, 0x57, 0x57, - 0x6b, 0x35, 0x26, 0x82, 0x80, 0x0b, 0xdc, 0x38, 0x72, 0xe3, 0x07, 0x08, 0x6e, 0x1c, 0xb9, 0x72, - 0x70, 0x70, 0xe2, 0xc8, 0x89, 0xc0, 0xfb, 0x09, 0x7c, 0x01, 0x51, 0xaf, 0x7e, 0xcc, 0x43, 0x06, - 0x85, 0x22, 0xb8, 0x4c, 0x54, 0x66, 0x65, 0xe5, 0xab, 0xaa, 0xb2, 0x32, 0xb3, 0x07, 0x3e, 0x1f, - 0x60, 0x36, 0x8c, 0x4f, 0xfb, 0x2e, 0xf1, 0x37, 0xce, 0x1d, 0xe6, 0xbc, 0xe1, 0x92, 0x80, 0x39, - 0x38, 0x40, 0x34, 0x9a, 0x82, 0x23, 0xea, 0x6e, 0x38, 0x03, 0x14, 0xb0, 0x8d, 0x90, 0x12, 0x46, - 0x5c, 0x32, 0x8a, 0xe4, 0x28, 0x92, 0xe8, 0xbe, 0x00, 0x8c, 0xf2, 0x80, 0x86, 0x6e, 0xaf, 0x46, - 0x5c, 0x2c, 0x11, 0xbd, 0x3a, 0x1b, 0x87, 0x28, 0x52, 0xc0, 0xf3, 0x03, 0x42, 0x06, 0x23, 0x24, - 0x17, 0x9e, 0xc6, 0x67, 0x1b, 0xc8, 0x0f, 0xd9, 0x58, 0x4e, 0x9a, 0x7f, 0x28, 0xc2, 0xea, 0x16, - 0x45, 0x0e, 0x43, 0x5b, 0x5a, 0xac, 0x85, 0xbe, 0x8a, 0x51, 0xc4, 0x8c, 0x97, 0xa0, 0x91, 0xa8, - 0x62, 0x63, 0xaf, 0x5b, 0xb8, 0x5b, 0x58, 0xaf, 0x59, 0xf5, 0x04, 0xb7, 0xef, 0x19, 0xb7, 0xa1, - 0x82, 0x2e, 0x91, 0xcb, 0x67, 0x8b, 0x62, 0x76, 0x91, 0x83, 0xfb, 0x9e, 0xf1, 0x16, 0xd4, 0x23, - 0x46, 0x71, 0x30, 0xb0, 0xe3, 0x08, 0xd1, 0x6e, 0xe9, 0x6e, 0x61, 0xbd, 0xfe, 0x60, 0xa9, 0xcf, - 0xf5, 0xec, 0x1f, 0x8b, 0x89, 0x93, 0x08, 0x51, 0x0b, 0xa2, 0x64, 0x6c, 0xdc, 0x87, 0x8a, 0x87, - 0x2e, 0xb0, 0x8b, 0xa2, 0x6e, 0xf9, 0x6e, 0x69, 0xbd, 0xfe, 0xa0, 0x21, 0xc9, 0xb7, 0x05, 0xd2, - 0xd2, 0x93, 0xc6, 0x6b, 0x50, 0x8d, 0x18, 0xa1, 0xce, 0x00, 0x45, 0xdd, 0x05, 0x41, 0xd8, 0xd4, - 0x7c, 0x05, 0xd6, 0x4a, 0xa6, 0x8d, 0x17, 0xa0, 0x74, 0xb8, 0xb5, 0xdf, 0x5d, 0x14, 0xd2, 0x41, - 0x51, 0x85, 0xc8, 0xb5, 0x38, 0xda, 0xb8, 0x07, 0xcd, 0xc8, 0x09, 0xbc, 0x53, 0x72, 0x69, 0x87, - 0xd8, 0x0b, 0xa2, 0x6e, 0xe5, 0x6e, 0x61, 0xbd, 0x6a, 0x35, 0x14, 0xf2, 0x88, 0xe3, 0xcc, 0xf7, - 0xe1, 0xd6, 0x31, 0x73, 0x28, 0xbb, 0x86, 0x77, 0xcc, 0x13, 0x58, 0xb5, 0x90, 0x4f, 0x2e, 0xae, - 0xe5, 0xda, 0x2e, 0x54, 0x18, 0xf6, 0x11, 0x89, 0x99, 0x70, 0x6d, 0xd3, 0xd2, 0xa0, 0xf9, 0xa7, - 0x02, 0x18, 0x3b, 0x97, 0xc8, 0x3d, 0xa2, 0xc4, 0x45, 0x51, 0xf4, 0x7f, 0xda, 0xae, 0x57, 0xa1, - 0x12, 0x4a, 0x05, 0xba, 0x65, 0x41, 0xae, 0x76, 0x41, 0x6b, 0xa5, 0x67, 0xcd, 0x2f, 0x61, 0xe5, - 0x18, 0x0f, 0x02, 0x67, 0x74, 0x83, 0xfa, 0xae, 0xc2, 0x62, 0x24, 0x78, 0x0a, 0x55, 0x9b, 0x96, - 0x82, 0xcc, 0x23, 0x30, 0xbe, 0x70, 0x30, 0xbb, 0x39, 0x49, 0xe6, 0x1b, 0xb0, 0x9c, 0xe3, 0x18, - 0x85, 0x24, 0x88, 0x90, 0x50, 0x80, 0x39, 0x2c, 0x8e, 0x04, 0xb3, 0x05, 0x4b, 0x41, 0x26, 0x81, - 0xd5, 0x93, 0xd0, 0xbb, 0xe6, 0x6d, 0x7a, 0x00, 0x35, 0x8a, 0x22, 0x12, 0x53, 0x7e, 0x07, 0x8a, - 0xc2, 0xa9, 0x2b, 0xd2, 0xa9, 0x9f, 0xe2, 0x20, 0xbe, 0xb4, 0xf4, 0x9c, 0x95, 0x92, 0xa9, 0xf3, - 0xc9, 0xa2, 0xeb, 0x9c, 0xcf, 0xf7, 0xe1, 0xd6, 0x91, 0x13, 0x47, 0xd7, 0xd1, 0xd5, 0xfc, 0x80, - 0x9f, 0xed, 0x28, 0xf6, 0xaf, 0xb5, 0xf8, 0x8f, 0x05, 0xa8, 0x6e, 0x85, 0xf1, 0x49, 0xe4, 0x0c, - 0x90, 0xf1, 0x3d, 0xa8, 0x33, 0xc2, 0x9c, 0x91, 0x1d, 0x73, 0x50, 0x90, 0x97, 0x2d, 0x10, 0x28, - 0x49, 0xf0, 0x12, 0x34, 0x42, 0x44, 0xdd, 0x30, 0x56, 0x14, 0xc5, 0xbb, 0xa5, 0xf5, 0xb2, 0x55, - 0x97, 0x38, 0x49, 0xd2, 0x87, 0x65, 0x31, 0x67, 0xe3, 0xc0, 0x3e, 0x47, 0x34, 0x40, 0x23, 0x9f, - 0x78, 0x48, 0x1c, 0x8e, 0xb2, 0xd5, 0x11, 0x53, 0xfb, 0xc1, 0x27, 0xc9, 0x84, 0xf1, 0x7d, 0xe8, - 0x24, 0xf4, 0xfc, 0xc4, 0x0b, 0xea, 0xb2, 0xa0, 0x6e, 0x2b, 0xea, 0x13, 0x85, 0x36, 0x7f, 0x09, - 0xad, 0x27, 0x43, 0x4a, 0x18, 0x1b, 0xe1, 0x60, 0xb0, 0xed, 0x30, 0x87, 0x5f, 0xcd, 0x10, 0x51, - 0x4c, 0xbc, 0x48, 0x69, 0xab, 0x41, 0xe3, 0x75, 0xe8, 0x30, 0x49, 0x8b, 0x3c, 0x5b, 0xd3, 0x14, - 0x05, 0xcd, 0x52, 0x32, 0x71, 0xa4, 0x88, 0x5f, 0x81, 0x56, 0x4a, 0xcc, 0x2f, 0xb7, 0xd2, 0xb7, - 0x99, 0x60, 0x9f, 0x60, 0x1f, 0x99, 0x17, 0xc2, 0x57, 0x62, 0x93, 0x8d, 0xd7, 0xa1, 0x96, 0xfa, - 0xa1, 0x20, 0x4e, 0x48, 0x4b, 0x9e, 0x10, 0xed, 0x4e, 0xab, 0x9a, 0x38, 0xe5, 0x43, 0x68, 0xb3, - 0x44, 0x71, 0xdb, 0x73, 0x98, 0x93, 0x3f, 0x54, 0x79, 0xab, 0xac, 0x16, 0xcb, 0xc1, 0xe6, 0x07, - 0x50, 0x3b, 0xc2, 0x5e, 0x24, 0x05, 0x77, 0xa1, 0xe2, 0xc6, 0x94, 0xa2, 0x80, 0x69, 0x93, 0x15, - 0x68, 0xac, 0xc0, 0xc2, 0x08, 0xfb, 0x98, 0x29, 0x33, 0x25, 0x60, 0x12, 0x80, 0x03, 0xe4, 0x13, - 0x3a, 0x16, 0x0e, 0x5b, 0x81, 0x85, 0xec, 0xe6, 0x4a, 0xc0, 0x78, 0x1e, 0x6a, 0xbe, 0x73, 0x99, - 0x6c, 0x2a, 0x9f, 0xa9, 0xfa, 0xce, 0xa5, 0x54, 0xbe, 0x0b, 0x95, 0x33, 0x07, 0x8f, 0xdc, 0x80, - 0x29, 0xaf, 0x68, 0x30, 0x15, 0x58, 0xce, 0x0a, 0xfc, 0x6b, 0x11, 0xea, 0x52, 0xa2, 0x54, 0x78, - 0x05, 0x16, 0x5c, 0xc7, 0x1d, 0x26, 0x22, 0x05, 0x60, 0xdc, 0xd7, 0x8a, 0x14, 0xb3, 0x11, 0x2e, - 0xd5, 0x54, 0xab, 0xb6, 0x01, 0x10, 0x3d, 0x75, 0x42, 0xa5, 0x5b, 0x69, 0x0e, 0x71, 0x8d, 0xd3, - 0x48, 0x75, 0xdf, 0x86, 0x86, 0x3c, 0x77, 0x6a, 0x49, 0x79, 0xce, 0x92, 0xba, 0xa4, 0x92, 0x8b, - 0xee, 0x41, 0x33, 0x8e, 0x90, 0x3d, 0xc4, 0x88, 0x3a, 0xd4, 0x1d, 0x8e, 0xbb, 0x0b, 0xf2, 0x01, - 0x8a, 0x23, 0xb4, 0xa7, 0x71, 0xc6, 0x03, 0x58, 0xe0, 0xb1, 0x25, 0xea, 0x2e, 0x8a, 0xb7, 0xee, - 0x85, 0x2c, 0x4b, 0x61, 0x6a, 0x5f, 0xfc, 0xee, 0x04, 0x8c, 0x8e, 0x2d, 0x49, 0xda, 0x7b, 0x17, - 0x20, 0x45, 0x1a, 0x4b, 0x50, 0x3a, 0x47, 0x63, 0x75, 0x0f, 0xf9, 0x90, 0x3b, 0xe7, 0xc2, 0x19, - 0xc5, 0xda, 0xeb, 0x12, 0x78, 0xbf, 0xf8, 0x6e, 0xc1, 0x74, 0xa1, 0xbd, 0x39, 0x3a, 0xc7, 0x24, - 0xb3, 0x7c, 0x05, 0x16, 0x7c, 0xe7, 0x4b, 0x42, 0xb5, 0x27, 0x05, 0x20, 0xb0, 0x38, 0x20, 0x54, - 0xb3, 0x10, 0x80, 0xd1, 0x82, 0x22, 0x09, 0x85, 0xbf, 0x6a, 0x56, 0x91, 0x84, 0xa9, 0xa0, 0x72, - 0x46, 0x90, 0xf9, 0xcf, 0x32, 0x40, 0x2a, 0xc5, 0xb0, 0xa0, 0x87, 0x89, 0x1d, 0x21, 0xca, 0xdf, - 0x77, 0xfb, 0x74, 0xcc, 0x50, 0x64, 0x53, 0xe4, 0xc6, 0x34, 0xc2, 0x17, 0x7c, 0xff, 0xb8, 0xd9, - 0xb7, 0xa4, 0xd9, 0x13, 0xba, 0x59, 0xb7, 0x31, 0x39, 0x96, 0xeb, 0x36, 0xf9, 0x32, 0x4b, 0xaf, - 0x32, 0xf6, 0xe1, 0x56, 0xca, 0xd3, 0xcb, 0xb0, 0x2b, 0x5e, 0xc5, 0x6e, 0x39, 0x61, 0xe7, 0xa5, - 0xac, 0x76, 0x60, 0x19, 0x13, 0xfb, 0xab, 0x18, 0xc5, 0x39, 0x46, 0xa5, 0xab, 0x18, 0x75, 0x30, - 0xf9, 0x5c, 0x2c, 0x48, 0xd9, 0x1c, 0xc1, 0x9d, 0x8c, 0x95, 0xfc, 0xba, 0x67, 0x98, 0x95, 0xaf, - 0x62, 0xb6, 0x9a, 0x68, 0xc5, 0xe3, 0x41, 0xca, 0xf1, 0x63, 0x58, 0xc5, 0xc4, 0x7e, 0xea, 0x60, - 0x36, 0xc9, 0x6e, 0xe1, 0x3b, 0x8c, 0xe4, 0x2f, 0x5a, 0x9e, 0x97, 0x34, 0xd2, 0x47, 0x74, 0x90, - 0x33, 0x72, 0xf1, 0x3b, 0x8c, 0x3c, 0x10, 0x0b, 0x52, 0x36, 0x8f, 0xa1, 0x83, 0xc9, 0xa4, 0x36, - 0x95, 0xab, 0x98, 0xb4, 0x31, 0xc9, 0x6b, 0xb2, 0x09, 0x9d, 0x08, 0xb9, 0x8c, 0xd0, 0xec, 0x21, - 0xa8, 0x5e, 0xc5, 0x62, 0x49, 0xd1, 0x27, 0x3c, 0xcc, 0x9f, 0x42, 0x63, 0x2f, 0x1e, 0x20, 0x36, - 0x3a, 0x4d, 0x82, 0xc1, 0x8d, 0xc5, 0x1f, 0xf3, 0xdf, 0x45, 0xa8, 0x6f, 0x0d, 0x28, 0x89, 0xc3, - 0x5c, 0x4c, 0x96, 0x97, 0x74, 0x32, 0x26, 0x0b, 0x12, 0x11, 0x93, 0x25, 0xf1, 0x3b, 0xd0, 0xf0, - 0xc5, 0xd5, 0x55, 0xf4, 0x32, 0x0e, 0x75, 0xa6, 0x2e, 0xb5, 0x55, 0xf7, 0x33, 0xc1, 0xac, 0x0f, - 0x10, 0x62, 0x2f, 0x52, 0x6b, 0x64, 0x38, 0x6a, 0xab, 0x74, 0x4b, 0x87, 0x68, 0xab, 0x16, 0x26, - 0xd1, 0xfa, 0x2d, 0xa8, 0x9f, 0x72, 0x27, 0xa9, 0x05, 0xb9, 0x60, 0x94, 0x7a, 0xcf, 0x82, 0xd3, - 0xf4, 0x12, 0xee, 0x41, 0x73, 0x28, 0x5d, 0xa6, 0x16, 0xc9, 0x33, 0x74, 0x4f, 0x59, 0x92, 0xda, - 0xdb, 0xcf, 0x7a, 0x56, 0x6e, 0x40, 0x63, 0x98, 0x41, 0xf5, 0x8e, 0xa1, 0x33, 0x45, 0x32, 0x23, - 0x06, 0xad, 0x67, 0x63, 0x50, 0xfd, 0x81, 0x21, 0x05, 0x65, 0x57, 0x66, 0xe3, 0xd2, 0xef, 0x8a, - 0xd0, 0xf8, 0x0c, 0xb1, 0xa7, 0x84, 0x9e, 0x4b, 0x7d, 0x0d, 0x28, 0x07, 0x8e, 0x8f, 0x14, 0x47, - 0x31, 0x36, 0xee, 0x40, 0x95, 0x5e, 0xca, 0x00, 0xa2, 0xf6, 0xb3, 0x42, 0x2f, 0x45, 0x60, 0x30, - 0x5e, 0x04, 0xa0, 0x97, 0x76, 0xe8, 0xb8, 0xe7, 0x48, 0x79, 0xb0, 0x6c, 0xd5, 0xe8, 0xe5, 0x91, - 0x44, 0xf0, 0xa3, 0x40, 0x2f, 0x6d, 0x44, 0x29, 0xa1, 0x91, 0x8a, 0x55, 0x55, 0x7a, 0xb9, 0x23, - 0x60, 0xb5, 0xd6, 0xa3, 0x24, 0x0c, 0x91, 0x27, 0x62, 0xb4, 0x58, 0xbb, 0x2d, 0x11, 0x5c, 0x2a, - 0xd3, 0x52, 0x17, 0xa5, 0x54, 0x96, 0x4a, 0x65, 0xa9, 0xd4, 0x8a, 0x5c, 0xc9, 0xb2, 0x52, 0x59, - 0x22, 0xb5, 0x2a, 0xa5, 0xb2, 0x8c, 0x54, 0x96, 0x4a, 0xad, 0xe9, 0xb5, 0x4a, 0xaa, 0xf9, 0xdb, - 0x02, 0xac, 0x4e, 0x26, 0x7e, 0x2a, 0x37, 0x7d, 0x07, 0x1a, 0xae, 0xd8, 0xaf, 0xdc, 0x99, 0xec, - 0x4c, 0xed, 0xa4, 0x55, 0x77, 0x33, 0xc7, 0xf8, 0x21, 0x34, 0x03, 0xe9, 0xe0, 0xe4, 0x68, 0x96, - 0xd2, 0x7d, 0xc9, 0xfa, 0xde, 0x6a, 0x04, 0x19, 0xc8, 0xf4, 0xc0, 0xf8, 0x82, 0x62, 0x86, 0x8e, - 0x19, 0x45, 0x8e, 0x7f, 0x13, 0xd9, 0xbd, 0x01, 0x65, 0x91, 0xad, 0xf0, 0x6d, 0x6a, 0x58, 0x62, - 0x6c, 0xbe, 0x0a, 0xcb, 0x39, 0x29, 0xca, 0xd6, 0x25, 0x28, 0x8d, 0x50, 0x20, 0xb8, 0x37, 0x2d, - 0x3e, 0x34, 0x1d, 0xe8, 0x58, 0xc8, 0xf1, 0x6e, 0x4e, 0x1b, 0x25, 0xa2, 0x94, 0x8a, 0x58, 0x07, - 0x23, 0x2b, 0x42, 0xa9, 0xa2, 0xb5, 0x2e, 0x64, 0xb4, 0x3e, 0x84, 0xce, 0xd6, 0x88, 0x44, 0xe8, - 0x98, 0x79, 0x38, 0xb8, 0x89, 0x72, 0xe4, 0x17, 0xb0, 0xfc, 0x84, 0x8d, 0xbf, 0xe0, 0xcc, 0x22, - 0xfc, 0x35, 0xba, 0x21, 0xfb, 0x28, 0x79, 0xaa, 0xed, 0xa3, 0xe4, 0x29, 0x2f, 0x6e, 0x5c, 0x32, - 0x8a, 0xfd, 0x40, 0x5c, 0x85, 0xa6, 0xa5, 0x20, 0x73, 0x13, 0x1a, 0x32, 0x87, 0x3e, 0x20, 0x5e, - 0x3c, 0x42, 0x33, 0xef, 0xe0, 0x1a, 0x40, 0xe8, 0x50, 0xc7, 0x47, 0x0c, 0x51, 0x79, 0x86, 0x6a, - 0x56, 0x06, 0x63, 0xfe, 0xbe, 0x08, 0x2b, 0xb2, 0xdf, 0x70, 0x2c, 0xcb, 0x6c, 0x6d, 0x42, 0x0f, - 0xaa, 0x43, 0x12, 0xb1, 0x0c, 0xc3, 0x04, 0xe6, 0x2a, 0xf2, 0xfa, 0x5c, 0x72, 0xe3, 0xc3, 0x5c, - 0x13, 0xa0, 0x74, 0x75, 0x13, 0x60, 0xaa, 0xcc, 0x2f, 0x4f, 0x97, 0xf9, 0xfc, 0xb6, 0x69, 0x22, - 0x2c, 0xef, 0x78, 0xcd, 0xaa, 0x29, 0xcc, 0xbe, 0x67, 0xdc, 0x87, 0xf6, 0x80, 0x6b, 0x69, 0x0f, - 0x09, 0x39, 0xb7, 0x43, 0x87, 0x0d, 0xc5, 0x55, 0xaf, 0x59, 0x4d, 0x81, 0xde, 0x23, 0xe4, 0xfc, - 0xc8, 0x61, 0x43, 0xe3, 0x3d, 0x68, 0xa9, 0x34, 0xd0, 0x17, 0x2e, 0x8a, 0xd4, 0xe3, 0xa7, 0x6e, - 0x51, 0xd6, 0x7b, 0x56, 0xf3, 0x3c, 0x03, 0x45, 0xe6, 0x6d, 0xb8, 0xb5, 0x8d, 0x22, 0x46, 0xc9, - 0x38, 0xef, 0x18, 0xf3, 0x47, 0x00, 0xfb, 0x01, 0x43, 0xf4, 0xcc, 0x71, 0x51, 0x64, 0xbc, 0x99, - 0x85, 0x54, 0x72, 0xb4, 0xd4, 0x97, 0xed, 0x9e, 0x64, 0xc2, 0xca, 0xd0, 0x98, 0x7d, 0x58, 0xb4, - 0x48, 0xcc, 0xc3, 0xd1, 0xcb, 0x7a, 0xa4, 0xd6, 0x35, 0xd4, 0x3a, 0x81, 0xb4, 0xd4, 0x9c, 0xb9, - 0xa7, 0x4b, 0xd8, 0x94, 0x9d, 0xda, 0xa2, 0x3e, 0xd4, 0xb0, 0xc6, 0xa9, 0xa8, 0x32, 0x2d, 0x3a, - 0x25, 0x31, 0x3f, 0x80, 0x65, 0xc9, 0x49, 0x72, 0xd6, 0x6c, 0x5e, 0x86, 0x45, 0xaa, 0xd5, 0x28, - 0xa4, 0x7d, 0x1e, 0x45, 0xa4, 0xe6, 0xb8, 0x3f, 0x3e, 0xc5, 0x11, 0x4b, 0x0d, 0xd1, 0xfe, 0x58, - 0x86, 0x0e, 0x9f, 0xc8, 0xf1, 0x34, 0x3f, 0x82, 0xc6, 0x63, 0xeb, 0xe8, 0x33, 0x84, 0x07, 0xc3, - 0x53, 0x1e, 0x3d, 0x7f, 0x98, 0x87, 0x95, 0xc1, 0x86, 0xd2, 0x36, 0x33, 0x65, 0xe5, 0xe8, 0xcc, - 0x8f, 0x61, 0xf5, 0xb1, 0xe7, 0x65, 0x51, 0x5a, 0xeb, 0x37, 0xa1, 0x16, 0x64, 0xd8, 0x65, 0xde, - 0xac, 0x1c, 0x75, 0x4a, 0x64, 0xfe, 0x0c, 0x96, 0x0f, 0x83, 0x11, 0x0e, 0xd0, 0xd6, 0xd1, 0xc9, - 0x01, 0x4a, 0x62, 0x91, 0x01, 0x65, 0x9e, 0xb3, 0x09, 0x1e, 0x55, 0x4b, 0x8c, 0xf9, 0xe5, 0x0c, - 0x4e, 0x6d, 0x37, 0x8c, 0x23, 0xd5, 0xec, 0x59, 0x0c, 0x4e, 0xb7, 0xc2, 0x38, 0xe2, 0x8f, 0x0b, - 0x4f, 0x2e, 0x48, 0x30, 0x1a, 0x8b, 0x1b, 0x5a, 0xb5, 0x2a, 0x6e, 0x18, 0x1f, 0x06, 0xa3, 0xb1, - 0xf9, 0x03, 0x51, 0x81, 0x23, 0xe4, 0x59, 0x4e, 0xe0, 0x11, 0x7f, 0x1b, 0x5d, 0x64, 0x24, 0x24, - 0xd5, 0x9e, 0x8e, 0x44, 0xdf, 0x14, 0xa0, 0xf1, 0x78, 0x80, 0x02, 0xb6, 0x8d, 0x98, 0x83, 0x47, - 0xa2, 0xa2, 0xbb, 0x40, 0x34, 0xc2, 0x24, 0x50, 0xd7, 0x4d, 0x83, 0xbc, 0x20, 0xc7, 0x01, 0x66, - 0xb6, 0xe7, 0x20, 0x9f, 0x04, 0x82, 0x4b, 0xd5, 0x02, 0x8e, 0xda, 0x16, 0x18, 0xe3, 0x55, 0x68, - 0xcb, 0x66, 0x9c, 0x3d, 0x74, 0x02, 0x6f, 0xc4, 0x2f, 0x7a, 0x49, 0x5c, 0xcd, 0x96, 0x44, 0xef, - 0x29, 0xac, 0xf1, 0x1a, 0x2c, 0xa9, 0x6b, 0x98, 0x52, 0x96, 0x05, 0x65, 0x5b, 0xe1, 0x73, 0xa4, - 0x71, 0x18, 0x12, 0xca, 0x22, 0x3b, 0x42, 0xae, 0x4b, 0xfc, 0x50, 0x95, 0x43, 0x6d, 0x8d, 0x3f, - 0x96, 0x68, 0x73, 0x00, 0xcb, 0xbb, 0xdc, 0x4e, 0x65, 0x49, 0x7a, 0xac, 0x5a, 0x3e, 0xf2, 0xed, - 0xd3, 0x11, 0x71, 0xcf, 0x6d, 0x1e, 0x1c, 0x95, 0x87, 0x79, 0xc2, 0xb5, 0xc9, 0x91, 0xc7, 0xf8, - 0x6b, 0x51, 0xf9, 0x73, 0xaa, 0x21, 0x61, 0xe1, 0x28, 0x1e, 0xd8, 0x21, 0x25, 0xa7, 0x48, 0x99, - 0xd8, 0xf6, 0x91, 0xbf, 0x27, 0xf1, 0x47, 0x1c, 0x6d, 0xfe, 0xa5, 0x00, 0x2b, 0x79, 0x49, 0x2a, - 0xd4, 0x6f, 0xc0, 0x4a, 0x5e, 0x94, 0x7a, 0xfe, 0x65, 0x7a, 0xd9, 0xc9, 0x0a, 0x94, 0x89, 0xc0, - 0x43, 0x68, 0x8a, 0x7e, 0xad, 0xed, 0x49, 0x4e, 0xf9, 0xa4, 0x27, 0xbb, 0x2f, 0x56, 0xc3, 0xc9, - 0xee, 0xd2, 0x7b, 0x70, 0x47, 0x99, 0x6f, 0x4f, 0xab, 0x2d, 0x0f, 0xc4, 0xaa, 0x22, 0x38, 0x98, - 0xd0, 0xfe, 0x53, 0xe8, 0xa6, 0xa8, 0xcd, 0xb1, 0x40, 0xa6, 0x87, 0x79, 0x79, 0xc2, 0xd8, 0xc7, - 0x9e, 0x47, 0xc5, 0x2d, 0x29, 0x5b, 0xb3, 0xa6, 0xcc, 0x47, 0x70, 0xfb, 0x18, 0x31, 0xe9, 0x0d, - 0x87, 0xa9, 0x4a, 0x44, 0x32, 0x5b, 0x82, 0xd2, 0x31, 0x72, 0x85, 0xf1, 0x25, 0x8b, 0x0f, 0xf9, - 0x01, 0x3c, 0x89, 0x90, 0x2b, 0xac, 0x2c, 0x59, 0x62, 0x6c, 0xfe, 0xb9, 0x00, 0x15, 0x15, 0x9c, - 0xf9, 0x03, 0xe3, 0x51, 0x7c, 0x81, 0xa8, 0x3a, 0x7a, 0x0a, 0x32, 0x5e, 0x81, 0x96, 0x1c, 0xd9, - 0x24, 0x64, 0x98, 0x24, 0x21, 0xbf, 0x29, 0xb1, 0x87, 0x12, 0x29, 0x9a, 0x6f, 0xa2, 0xfd, 0xa5, - 0x2a, 0x4d, 0x05, 0x71, 0xfc, 0x59, 0xc4, 0x6f, 0xb8, 0x08, 0xf1, 0x35, 0x4b, 0x41, 0xfc, 0xa8, - 0x6b, 0x7e, 0x0b, 0x82, 0x9f, 0x06, 0xf9, 0x51, 0xf7, 0x49, 0x1c, 0x30, 0x3b, 0x24, 0x38, 0x60, - 0x2a, 0xa6, 0x83, 0x40, 0x1d, 0x71, 0x8c, 0xf9, 0x9b, 0x02, 0x2c, 0xca, 0x06, 0x34, 0xaf, 0x6d, - 0x93, 0x97, 0xb5, 0x88, 0x45, 0x96, 0x22, 0x64, 0xc9, 0xd7, 0x54, 0x8c, 0xf9, 0x3d, 0xbe, 0xf0, - 0xe5, 0xfb, 0xa0, 0x54, 0xbb, 0xf0, 0xc5, 0xc3, 0xf0, 0x0a, 0xb4, 0xd2, 0x07, 0x5a, 0xcc, 0x4b, - 0x15, 0x9b, 0x09, 0x56, 0x90, 0xcd, 0xd5, 0xd4, 0xfc, 0x31, 0x2f, 0xe9, 0x93, 0xe6, 0xeb, 0x12, - 0x94, 0xe2, 0x44, 0x19, 0x3e, 0xe4, 0x98, 0x41, 0xf2, 0xb4, 0xf3, 0xa1, 0x71, 0x1f, 0x5a, 0x8e, - 0xe7, 0x61, 0xbe, 0xdc, 0x19, 0xed, 0x62, 0x2f, 0xb9, 0xa4, 0x79, 0xac, 0xf9, 0xb7, 0x02, 0xb4, - 0xb7, 0x48, 0x38, 0xfe, 0x08, 0x8f, 0x50, 0x26, 0x82, 0x08, 0x25, 0xd5, 0xcb, 0xce, 0xc7, 0x3c, - 0x5b, 0x3d, 0xc3, 0x23, 0x24, 0xaf, 0x96, 0xdc, 0xd9, 0x2a, 0x47, 0x88, 0x6b, 0xa5, 0x27, 0x93, - 0xb6, 0x5b, 0x53, 0x4e, 0x1e, 0x10, 0x4f, 0xe4, 0xe5, 0x1e, 0xa6, 0x76, 0xd2, 0x64, 0x6b, 0x5a, - 0x15, 0x0f, 0x53, 0x31, 0xa5, 0x0c, 0x59, 0x10, 0x4d, 0xd4, 0xac, 0x21, 0x8b, 0x12, 0xc3, 0x0d, - 0x59, 0x85, 0x45, 0x72, 0x76, 0x16, 0x21, 0x26, 0x32, 0xe8, 0x92, 0xa5, 0xa0, 0x24, 0xcc, 0x55, - 0x33, 0x61, 0xee, 0x16, 0x2c, 0x8b, 0x76, 0xfd, 0x13, 0xea, 0xb8, 0x38, 0x18, 0xe8, 0xe7, 0x61, - 0x05, 0x8c, 0x63, 0x46, 0xc2, 0x69, 0xec, 0x2e, 0x62, 0x87, 0x87, 0x07, 0x3b, 0x17, 0x28, 0x60, - 0x1a, 0xfb, 0x06, 0x54, 0x35, 0xea, 0xbf, 0xe9, 0x65, 0x2e, 0x43, 0x67, 0x17, 0xb1, 0x03, 0xc4, - 0x28, 0x76, 0x93, 0xe7, 0xe8, 0x1e, 0x54, 0x14, 0x86, 0x6f, 0xa9, 0x2f, 0x87, 0x3a, 0xce, 0x2a, - 0xf0, 0xc1, 0xaf, 0x3b, 0x2a, 0x24, 0xab, 0xea, 0xde, 0xd8, 0x85, 0xf6, 0xc4, 0xa7, 0x18, 0x43, - 0xb5, 0x7b, 0x66, 0x7f, 0xa1, 0xe9, 0xad, 0xf6, 0xe5, 0xa7, 0x9d, 0xbe, 0xfe, 0xb4, 0xd3, 0xdf, - 0xf1, 0x43, 0x36, 0x36, 0x76, 0xa0, 0x95, 0xff, 0x68, 0x61, 0x3c, 0xaf, 0xb3, 0xa3, 0x19, 0x9f, - 0x32, 0xe6, 0xb2, 0xd9, 0x85, 0xf6, 0xc4, 0xf7, 0x0b, 0xad, 0xcf, 0xec, 0xcf, 0x1a, 0x73, 0x19, - 0x3d, 0x82, 0x7a, 0xe6, 0x83, 0x85, 0xd1, 0x95, 0x4c, 0xa6, 0xbf, 0x61, 0xcc, 0x65, 0xb0, 0x05, - 0xcd, 0xdc, 0x37, 0x04, 0xa3, 0xa7, 0xec, 0x99, 0xf1, 0x61, 0x61, 0x2e, 0x93, 0x4d, 0xa8, 0x67, - 0x5a, 0xf9, 0x5a, 0x8b, 0xe9, 0xef, 0x05, 0xbd, 0x3b, 0x33, 0x66, 0x54, 0xe4, 0xdf, 0x85, 0xf6, - 0x44, 0x7f, 0x5f, 0xbb, 0x64, 0x76, 0xdb, 0x7f, 0xae, 0x32, 0x9f, 0x88, 0x2d, 0xca, 0x94, 0x6f, - 0x99, 0x2d, 0x9a, 0xee, 0xe6, 0xf7, 0x5e, 0x98, 0x3d, 0xa9, 0xb4, 0xda, 0x81, 0x56, 0xbe, 0x91, - 0xaf, 0x99, 0xcd, 0x6c, 0xef, 0x5f, 0xbd, 0xdf, 0xb9, 0x9e, 0x7e, 0xba, 0xdf, 0xb3, 0x5a, 0xfd, - 0x73, 0x19, 0x3d, 0x06, 0x50, 0xc5, 0x9a, 0x87, 0x83, 0xc4, 0xd1, 0x53, 0x45, 0x62, 0xe2, 0xe8, - 0x19, 0x85, 0xdd, 0x23, 0x00, 0x59, 0x63, 0x79, 0x24, 0x66, 0xc6, 0x6d, 0xad, 0xc6, 0x44, 0x61, - 0xd7, 0xeb, 0x4e, 0x4f, 0x4c, 0x31, 0x40, 0x94, 0x5e, 0x87, 0xc1, 0x87, 0x00, 0x69, 0xed, 0xa6, - 0x19, 0x4c, 0x55, 0x73, 0x57, 0xf8, 0xa0, 0x91, 0xad, 0xd4, 0x0c, 0x65, 0xeb, 0x8c, 0xea, 0xed, - 0x0a, 0x16, 0xed, 0x89, 0x4c, 0x3c, 0x7f, 0xd8, 0x26, 0x13, 0xf4, 0xde, 0x54, 0x36, 0x6e, 0x3c, - 0x84, 0x46, 0x36, 0x05, 0xd7, 0x5a, 0xcc, 0x48, 0xcb, 0x7b, 0xb9, 0x34, 0xdc, 0x78, 0x04, 0xad, - 0x7c, 0xfa, 0xad, 0x8f, 0xd4, 0xcc, 0xa4, 0xbc, 0xa7, 0x9a, 0x4b, 0x19, 0xf2, 0xb7, 0x01, 0xd2, - 0x34, 0x5d, 0xbb, 0x6f, 0x2a, 0x71, 0x9f, 0x90, 0xba, 0x0b, 0xed, 0x89, 0xf4, 0x5b, 0x5b, 0x3c, - 0x3b, 0x2b, 0xbf, 0xca, 0xfb, 0xd9, 0x77, 0x40, 0xdb, 0x3d, 0xe3, 0x6d, 0xb8, 0x2a, 0x68, 0x65, - 0xde, 0x0c, 0x7d, 0x8a, 0xa7, 0x9f, 0x91, 0xb9, 0x0c, 0xde, 0x01, 0x48, 0x5f, 0x06, 0xed, 0x81, - 0xa9, 0xb7, 0xa2, 0xd7, 0xd4, 0xcd, 0x3f, 0x49, 0xb7, 0x05, 0xcd, 0x5c, 0x7d, 0xac, 0x43, 0xdd, - 0xac, 0xa2, 0xf9, 0xaa, 0x07, 0x20, 0x5f, 0x4c, 0xea, 0xdd, 0x9b, 0x59, 0x62, 0x5e, 0xe5, 0xc5, - 0x6c, 0x05, 0xa3, 0xbd, 0x38, 0xa3, 0xaa, 0xf9, 0x8e, 0x98, 0x92, 0xad, 0x52, 0x32, 0x31, 0x65, - 0x46, 0xf1, 0x32, 0x97, 0xd1, 0x1e, 0xb4, 0x77, 0x75, 0x02, 0xaa, 0x92, 0x63, 0xa5, 0xce, 0x8c, - 0x62, 0xa0, 0xd7, 0x9b, 0x35, 0xa5, 0x2e, 0xf6, 0x27, 0xd0, 0x99, 0x4a, 0x8c, 0x8d, 0xb5, 0xa4, - 0x05, 0x3b, 0x33, 0x63, 0x9e, 0xab, 0xd6, 0x3e, 0x2c, 0x4d, 0xe6, 0xc5, 0xc6, 0x8b, 0xea, 0xa8, - 0xcc, 0xce, 0x97, 0xe7, 0xb2, 0x7a, 0x0f, 0xaa, 0x3a, 0x0f, 0x33, 0x54, 0xab, 0x7b, 0x22, 0x2f, - 0x9b, 0xbb, 0xf4, 0x21, 0xd4, 0x33, 0x99, 0x8c, 0x3e, 0xab, 0xd3, 0xc9, 0x4d, 0x4f, 0x75, 0xa6, - 0x35, 0x7a, 0xf3, 0xf2, 0x9b, 0x6f, 0xd7, 0x9e, 0xfb, 0xc7, 0xb7, 0x6b, 0xcf, 0xfd, 0xea, 0xd9, - 0x5a, 0xe1, 0x9b, 0x67, 0x6b, 0x85, 0xbf, 0x3f, 0x5b, 0x2b, 0xfc, 0xeb, 0xd9, 0x5a, 0xe1, 0x27, - 0x3f, 0xff, 0x1f, 0xff, 0xa6, 0x42, 0xe3, 0x80, 0x61, 0x1f, 0x6d, 0x5c, 0x60, 0xca, 0x32, 0x53, - 0xe1, 0xf9, 0x60, 0xea, 0x1f, 0x2c, 0x5c, 0x85, 0xd3, 0x45, 0x01, 0xbf, 0xfd, 0x9f, 0x00, 0x00, - 0x00, 0xff, 0xff, 0x23, 0xa0, 0xd8, 0x6f, 0x0f, 0x23, 0x00, 0x00, + // 2982 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x1a, 0xcb, 0x6e, 0x1c, 0xc7, + 0xd1, 0xfb, 0x20, 0x77, 0xb7, 0xf6, 0xc5, 0x1d, 0x52, 0xd4, 0x6a, 0x6d, 0x33, 0xf2, 0xc8, 0x96, + 0xe5, 0x38, 0x5e, 0xd9, 0xb2, 0x11, 0xf9, 0x01, 0x47, 0x10, 0x29, 0x9a, 0xa4, 0x6d, 0x5a, 0xf4, + 0x50, 0x82, 0x83, 0x04, 0xc9, 0x60, 0x38, 0xd3, 0xda, 0x6d, 0x73, 0x67, 0x7a, 0xdc, 0xdd, 0x43, + 0x71, 0x1d, 0x20, 0x48, 0x2e, 0xc9, 0x2d, 0xc7, 0xdc, 0xf2, 0x03, 0x41, 0x6e, 0x39, 0xe6, 0x9a, + 0x83, 0x91, 0x53, 0x8e, 0x39, 0x05, 0xb1, 0x3e, 0x21, 0x5f, 0x10, 0xf4, 0x6b, 0x1e, 0xfb, 0xa0, + 0x13, 0x41, 0x40, 0x2e, 0x8b, 0xae, 0xea, 0xea, 0x7a, 0x75, 0x77, 0x75, 0x55, 0xcd, 0xc2, 0xe7, + 0x23, 0xcc, 0xc7, 0xc9, 0xc9, 0xd0, 0x27, 0xe1, 0xcd, 0x53, 0x8f, 0x7b, 0x6f, 0xf8, 0x24, 0xe2, + 0x1e, 0x8e, 0x10, 0x65, 0x73, 0x30, 0xa3, 0xfe, 0x4d, 0x6f, 0x84, 0x22, 0x7e, 0x33, 0xa6, 0x84, + 0x13, 0x9f, 0x4c, 0x98, 0x1a, 0x31, 0x85, 0x1e, 0x4a, 0xc0, 0xaa, 0x8e, 0x68, 0xec, 0x0f, 0x1a, + 0xc4, 0xc7, 0x0a, 0x31, 0x68, 0xf2, 0x69, 0x8c, 0x98, 0x06, 0x9e, 0x1f, 0x11, 0x32, 0x9a, 0x20, + 0xb5, 0xf0, 0x24, 0x79, 0x74, 0x13, 0x85, 0x31, 0x9f, 0xaa, 0x49, 0xfb, 0x0f, 0x65, 0xd8, 0xdc, + 0xa1, 0xc8, 0xe3, 0x68, 0xc7, 0x88, 0x75, 0xd0, 0x57, 0x09, 0x62, 0xdc, 0x7a, 0x09, 0x5a, 0xa9, + 0x2a, 0x2e, 0x0e, 0xfa, 0xa5, 0xab, 0xa5, 0x1b, 0x0d, 0xa7, 0x99, 0xe2, 0x0e, 0x02, 0xeb, 0x32, + 0xd4, 0xd0, 0x39, 0xf2, 0xc5, 0x6c, 0x59, 0xce, 0xae, 0x0a, 0xf0, 0x20, 0xb0, 0xde, 0x82, 0x26, + 0xe3, 0x14, 0x47, 0x23, 0x37, 0x61, 0x88, 0xf6, 0x2b, 0x57, 0x4b, 0x37, 0x9a, 0xb7, 0xd6, 0x86, + 0x42, 0xcf, 0xe1, 0xb1, 0x9c, 0x78, 0xc8, 0x10, 0x75, 0x80, 0xa5, 0x63, 0xeb, 0x3a, 0xd4, 0x02, + 0x74, 0x86, 0x7d, 0xc4, 0xfa, 0xd5, 0xab, 0x95, 0x1b, 0xcd, 0x5b, 0x2d, 0x45, 0x7e, 0x4f, 0x22, + 0x1d, 0x33, 0x69, 0xbd, 0x06, 0x75, 0xc6, 0x09, 0xf5, 0x46, 0x88, 0xf5, 0x57, 0x24, 0x61, 0xdb, + 0xf0, 0x95, 0x58, 0x27, 0x9d, 0xb6, 0x5e, 0x80, 0xca, 0xfd, 0x9d, 0x83, 0xfe, 0xaa, 0x94, 0x0e, + 0x9a, 0x2a, 0x46, 0xbe, 0x53, 0x21, 0x3b, 0x07, 0xd6, 0x35, 0x68, 0x33, 0x2f, 0x0a, 0x4e, 0xc8, + 0xb9, 0x1b, 0xe3, 0x20, 0x62, 0xfd, 0xda, 0xd5, 0xd2, 0x8d, 0xba, 0xd3, 0xd2, 0xc8, 0x23, 0x81, + 0xb3, 0xdf, 0x87, 0x4b, 0xc7, 0xdc, 0xa3, 0xfc, 0x29, 0xbc, 0x63, 0x3f, 0x84, 0x4d, 0x07, 0x85, + 0xe4, 0xec, 0xa9, 0x5c, 0xdb, 0x87, 0x1a, 0xc7, 0x21, 0x22, 0x09, 0x97, 0xae, 0x6d, 0x3b, 0x06, + 0xb4, 0xff, 0x54, 0x02, 0x6b, 0xf7, 0x1c, 0xf9, 0x47, 0x94, 0xf8, 0x88, 0xb1, 0xff, 0xd3, 0x76, + 0xbd, 0x0a, 0xb5, 0x58, 0x29, 0xd0, 0xaf, 0x4a, 0x72, 0xbd, 0x0b, 0x46, 0x2b, 0x33, 0x6b, 0x7f, + 0x09, 0x1b, 0xc7, 0x78, 0x14, 0x79, 0x93, 0x67, 0xa8, 0xef, 0x26, 0xac, 0x32, 0xc9, 0x53, 0xaa, + 0xda, 0x76, 0x34, 0x64, 0x1f, 0x81, 0xf5, 0x85, 0x87, 0xf9, 0xb3, 0x93, 0x64, 0xbf, 0x01, 0xeb, + 0x05, 0x8e, 0x2c, 0x26, 0x11, 0x43, 0x52, 0x01, 0xee, 0xf1, 0x84, 0x49, 0x66, 0x2b, 0x8e, 0x86, + 0x6c, 0x02, 0x9b, 0x0f, 0xe3, 0xe0, 0x29, 0x6f, 0xd3, 0x2d, 0x68, 0x50, 0xc4, 0x48, 0x42, 0xc5, + 0x1d, 0x28, 0x4b, 0xa7, 0x6e, 0x28, 0xa7, 0x7e, 0x8a, 0xa3, 0xe4, 0xdc, 0x31, 0x73, 0x4e, 0x46, + 0xa6, 0xcf, 0x27, 0x67, 0x4f, 0x73, 0x3e, 0xdf, 0x87, 0x4b, 0x47, 0x5e, 0xc2, 0x9e, 0x46, 0x57, + 0xfb, 0x03, 0x71, 0xb6, 0x59, 0x12, 0x3e, 0xd5, 0xe2, 0x3f, 0x96, 0xa0, 0xbe, 0x13, 0x27, 0x0f, + 0x99, 0x37, 0x42, 0xd6, 0xf7, 0xa0, 0xc9, 0x09, 0xf7, 0x26, 0x6e, 0x22, 0x40, 0x49, 0x5e, 0x75, + 0x40, 0xa2, 0x14, 0xc1, 0x4b, 0xd0, 0x8a, 0x11, 0xf5, 0xe3, 0x44, 0x53, 0x94, 0xaf, 0x56, 0x6e, + 0x54, 0x9d, 0xa6, 0xc2, 0x29, 0x92, 0x21, 0xac, 0xcb, 0x39, 0x17, 0x47, 0xee, 0x29, 0xa2, 0x11, + 0x9a, 0x84, 0x24, 0x40, 0xf2, 0x70, 0x54, 0x9d, 0x9e, 0x9c, 0x3a, 0x88, 0x3e, 0x49, 0x27, 0xac, + 0xef, 0x43, 0x2f, 0xa5, 0x17, 0x27, 0x5e, 0x52, 0x57, 0x25, 0x75, 0x57, 0x53, 0x3f, 0xd4, 0x68, + 0xfb, 0x97, 0xd0, 0x79, 0x30, 0xa6, 0x84, 0xf3, 0x09, 0x8e, 0x46, 0xf7, 0x3c, 0xee, 0x89, 0xab, + 0x19, 0x23, 0x8a, 0x49, 0xc0, 0xb4, 0xb6, 0x06, 0xb4, 0x5e, 0x87, 0x1e, 0x57, 0xb4, 0x28, 0x70, + 0x0d, 0x4d, 0x59, 0xd2, 0xac, 0xa5, 0x13, 0x47, 0x9a, 0xf8, 0x15, 0xe8, 0x64, 0xc4, 0xe2, 0x72, + 0x6b, 0x7d, 0xdb, 0x29, 0xf6, 0x01, 0x0e, 0x91, 0x7d, 0x26, 0x7d, 0x25, 0x37, 0xd9, 0x7a, 0x1d, + 0x1a, 0x99, 0x1f, 0x4a, 0xf2, 0x84, 0x74, 0xd4, 0x09, 0x31, 0xee, 0x74, 0xea, 0xa9, 0x53, 0x3e, + 0x84, 0x2e, 0x4f, 0x15, 0x77, 0x03, 0x8f, 0x7b, 0xc5, 0x43, 0x55, 0xb4, 0xca, 0xe9, 0xf0, 0x02, + 0x6c, 0x7f, 0x00, 0x8d, 0x23, 0x1c, 0x30, 0x25, 0xb8, 0x0f, 0x35, 0x3f, 0xa1, 0x14, 0x45, 0xdc, + 0x98, 0xac, 0x41, 0x6b, 0x03, 0x56, 0x26, 0x38, 0xc4, 0x5c, 0x9b, 0xa9, 0x00, 0x9b, 0x00, 0x1c, + 0xa2, 0x90, 0xd0, 0xa9, 0x74, 0xd8, 0x06, 0xac, 0xe4, 0x37, 0x57, 0x01, 0xd6, 0xf3, 0xd0, 0x08, + 0xbd, 0xf3, 0x74, 0x53, 0xc5, 0x4c, 0x3d, 0xf4, 0xce, 0x95, 0xf2, 0x7d, 0xa8, 0x3d, 0xf2, 0xf0, + 0xc4, 0x8f, 0xb8, 0xf6, 0x8a, 0x01, 0x33, 0x81, 0xd5, 0xbc, 0xc0, 0xbf, 0x96, 0xa1, 0xa9, 0x24, + 0x2a, 0x85, 0x37, 0x60, 0xc5, 0xf7, 0xfc, 0x71, 0x2a, 0x52, 0x02, 0xd6, 0x75, 0xa3, 0x48, 0x39, + 0x1f, 0xe1, 0x32, 0x4d, 0x8d, 0x6a, 0x37, 0x01, 0xd8, 0x63, 0x2f, 0xd6, 0xba, 0x55, 0x96, 0x10, + 0x37, 0x04, 0x8d, 0x52, 0xf7, 0x6d, 0x68, 0xa9, 0x73, 0xa7, 0x97, 0x54, 0x97, 0x2c, 0x69, 0x2a, + 0x2a, 0xb5, 0xe8, 0x1a, 0xb4, 0x13, 0x86, 0xdc, 0x31, 0x46, 0xd4, 0xa3, 0xfe, 0x78, 0xda, 0x5f, + 0x51, 0x0f, 0x50, 0xc2, 0xd0, 0xbe, 0xc1, 0x59, 0xb7, 0x60, 0x45, 0xc4, 0x16, 0xd6, 0x5f, 0x95, + 0x6f, 0xdd, 0x0b, 0x79, 0x96, 0xd2, 0xd4, 0xa1, 0xfc, 0xdd, 0x8d, 0x38, 0x9d, 0x3a, 0x8a, 0x74, + 0xf0, 0x2e, 0x40, 0x86, 0xb4, 0xd6, 0xa0, 0x72, 0x8a, 0xa6, 0xfa, 0x1e, 0x8a, 0xa1, 0x70, 0xce, + 0x99, 0x37, 0x49, 0x8c, 0xd7, 0x15, 0xf0, 0x7e, 0xf9, 0xdd, 0x92, 0xed, 0x43, 0x77, 0x7b, 0x72, + 0x8a, 0x49, 0x6e, 0xf9, 0x06, 0xac, 0x84, 0xde, 0x97, 0x84, 0x1a, 0x4f, 0x4a, 0x40, 0x62, 0x71, + 0x44, 0xa8, 0x61, 0x21, 0x01, 0xab, 0x03, 0x65, 0x12, 0x4b, 0x7f, 0x35, 0x9c, 0x32, 0x89, 0x33, + 0x41, 0xd5, 0x9c, 0x20, 0xfb, 0x9f, 0x55, 0x80, 0x4c, 0x8a, 0xe5, 0xc0, 0x00, 0x13, 0x97, 0x21, + 0x2a, 0xde, 0x77, 0xf7, 0x64, 0xca, 0x11, 0x73, 0x29, 0xf2, 0x13, 0xca, 0xf0, 0x99, 0xd8, 0x3f, + 0x61, 0xf6, 0x25, 0x65, 0xf6, 0x8c, 0x6e, 0xce, 0x65, 0x4c, 0x8e, 0xd5, 0xba, 0x6d, 0xb1, 0xcc, + 0x31, 0xab, 0xac, 0x03, 0xb8, 0x94, 0xf1, 0x0c, 0x72, 0xec, 0xca, 0x17, 0xb1, 0x5b, 0x4f, 0xd9, + 0x05, 0x19, 0xab, 0x5d, 0x58, 0xc7, 0xc4, 0xfd, 0x2a, 0x41, 0x49, 0x81, 0x51, 0xe5, 0x22, 0x46, + 0x3d, 0x4c, 0x3e, 0x97, 0x0b, 0x32, 0x36, 0x47, 0x70, 0x25, 0x67, 0xa5, 0xb8, 0xee, 0x39, 0x66, + 0xd5, 0x8b, 0x98, 0x6d, 0xa6, 0x5a, 0x89, 0x78, 0x90, 0x71, 0xfc, 0x18, 0x36, 0x31, 0x71, 0x1f, + 0x7b, 0x98, 0xcf, 0xb2, 0x5b, 0xf9, 0x0e, 0x23, 0xc5, 0x8b, 0x56, 0xe4, 0xa5, 0x8c, 0x0c, 0x11, + 0x1d, 0x15, 0x8c, 0x5c, 0xfd, 0x0e, 0x23, 0x0f, 0xe5, 0x82, 0x8c, 0xcd, 0x5d, 0xe8, 0x61, 0x32, + 0xab, 0x4d, 0xed, 0x22, 0x26, 0x5d, 0x4c, 0x8a, 0x9a, 0x6c, 0x43, 0x8f, 0x21, 0x9f, 0x13, 0x9a, + 0x3f, 0x04, 0xf5, 0x8b, 0x58, 0xac, 0x69, 0xfa, 0x94, 0x87, 0xfd, 0x53, 0x68, 0xed, 0x27, 0x23, + 0xc4, 0x27, 0x27, 0x69, 0x30, 0x78, 0x66, 0xf1, 0xc7, 0xfe, 0x77, 0x19, 0x9a, 0x3b, 0x23, 0x4a, + 0x92, 0xb8, 0x10, 0x93, 0xd5, 0x25, 0x9d, 0x8d, 0xc9, 0x92, 0x44, 0xc6, 0x64, 0x45, 0xfc, 0x0e, + 0xb4, 0x42, 0x79, 0x75, 0x35, 0xbd, 0x8a, 0x43, 0xbd, 0xb9, 0x4b, 0xed, 0x34, 0xc3, 0x5c, 0x30, + 0x1b, 0x02, 0xc4, 0x38, 0x60, 0x7a, 0x8d, 0x0a, 0x47, 0x5d, 0x9d, 0x6e, 0x99, 0x10, 0xed, 0x34, + 0xe2, 0x34, 0x5a, 0xbf, 0x05, 0xcd, 0x13, 0xe1, 0x24, 0xbd, 0xa0, 0x10, 0x8c, 0x32, 0xef, 0x39, + 0x70, 0x92, 0x5d, 0xc2, 0x7d, 0x68, 0x8f, 0x95, 0xcb, 0xf4, 0x22, 0x75, 0x86, 0xae, 0x69, 0x4b, + 0x32, 0x7b, 0x87, 0x79, 0xcf, 0xaa, 0x0d, 0x68, 0x8d, 0x73, 0xa8, 0xc1, 0x31, 0xf4, 0xe6, 0x48, + 0x16, 0xc4, 0xa0, 0x1b, 0xf9, 0x18, 0xd4, 0xbc, 0x65, 0x29, 0x41, 0xf9, 0x95, 0xf9, 0xb8, 0xf4, + 0xbb, 0x32, 0xb4, 0x3e, 0x43, 0xfc, 0x31, 0xa1, 0xa7, 0x4a, 0x5f, 0x0b, 0xaa, 0x91, 0x17, 0x22, + 0xcd, 0x51, 0x8e, 0xad, 0x2b, 0x50, 0xa7, 0xe7, 0x2a, 0x80, 0xe8, 0xfd, 0xac, 0xd1, 0x73, 0x19, + 0x18, 0xac, 0x17, 0x01, 0xe8, 0xb9, 0x1b, 0x7b, 0xfe, 0x29, 0xd2, 0x1e, 0xac, 0x3a, 0x0d, 0x7a, + 0x7e, 0xa4, 0x10, 0xe2, 0x28, 0xd0, 0x73, 0x17, 0x51, 0x4a, 0x28, 0xd3, 0xb1, 0xaa, 0x4e, 0xcf, + 0x77, 0x25, 0xac, 0xd7, 0x06, 0x94, 0xc4, 0x31, 0x0a, 0x64, 0x8c, 0x96, 0x6b, 0xef, 0x29, 0x84, + 0x90, 0xca, 0x8d, 0xd4, 0x55, 0x25, 0x95, 0x67, 0x52, 0x79, 0x26, 0xb5, 0xa6, 0x56, 0xf2, 0xbc, + 0x54, 0x9e, 0x4a, 0xad, 0x2b, 0xa9, 0x3c, 0x27, 0x95, 0x67, 0x52, 0x1b, 0x66, 0xad, 0x96, 0x6a, + 0xff, 0xb6, 0x04, 0x9b, 0xb3, 0x89, 0x9f, 0xce, 0x4d, 0xdf, 0x81, 0x96, 0x2f, 0xf7, 0xab, 0x70, + 0x26, 0x7b, 0x73, 0x3b, 0xe9, 0x34, 0xfd, 0xdc, 0x31, 0xbe, 0x0d, 0xed, 0x48, 0x39, 0x38, 0x3d, + 0x9a, 0x95, 0x6c, 0x5f, 0xf2, 0xbe, 0x77, 0x5a, 0x51, 0x0e, 0xb2, 0x03, 0xb0, 0xbe, 0xa0, 0x98, + 0xa3, 0x63, 0x4e, 0x91, 0x17, 0x3e, 0x8b, 0xec, 0xde, 0x82, 0xaa, 0xcc, 0x56, 0xc4, 0x36, 0xb5, + 0x1c, 0x39, 0xb6, 0x5f, 0x85, 0xf5, 0x82, 0x14, 0x6d, 0xeb, 0x1a, 0x54, 0x26, 0x28, 0x92, 0xdc, + 0xdb, 0x8e, 0x18, 0xda, 0x1e, 0xf4, 0x1c, 0xe4, 0x05, 0xcf, 0x4e, 0x1b, 0x2d, 0xa2, 0x92, 0x89, + 0xb8, 0x01, 0x56, 0x5e, 0x84, 0x56, 0xc5, 0x68, 0x5d, 0xca, 0x69, 0x7d, 0x1f, 0x7a, 0x3b, 0x13, + 0xc2, 0xd0, 0x31, 0x0f, 0x70, 0xf4, 0x2c, 0xca, 0x91, 0x5f, 0xc0, 0xfa, 0x03, 0x3e, 0xfd, 0x42, + 0x30, 0x63, 0xf8, 0x6b, 0xf4, 0x8c, 0xec, 0xa3, 0xe4, 0xb1, 0xb1, 0x8f, 0x92, 0xc7, 0xa2, 0xb8, + 0xf1, 0xc9, 0x24, 0x09, 0x23, 0x79, 0x15, 0xda, 0x8e, 0x86, 0xec, 0x6d, 0x68, 0xa9, 0x1c, 0xfa, + 0x90, 0x04, 0xc9, 0x04, 0x2d, 0xbc, 0x83, 0x5b, 0x00, 0xb1, 0x47, 0xbd, 0x10, 0x71, 0x44, 0xd5, + 0x19, 0x6a, 0x38, 0x39, 0x8c, 0xfd, 0xfb, 0x32, 0x6c, 0xa8, 0x7e, 0xc3, 0xb1, 0x2a, 0xb3, 0x8d, + 0x09, 0x03, 0xa8, 0x8f, 0x09, 0xe3, 0x39, 0x86, 0x29, 0x2c, 0x54, 0x14, 0xf5, 0xb9, 0xe2, 0x26, + 0x86, 0x85, 0x26, 0x40, 0xe5, 0xe2, 0x26, 0xc0, 0x5c, 0x99, 0x5f, 0x9d, 0x2f, 0xf3, 0xc5, 0x6d, + 0x33, 0x44, 0x58, 0xdd, 0xf1, 0x86, 0xd3, 0xd0, 0x98, 0x83, 0xc0, 0xba, 0x0e, 0xdd, 0x91, 0xd0, + 0xd2, 0x1d, 0x13, 0x72, 0xea, 0xc6, 0x1e, 0x1f, 0xcb, 0xab, 0xde, 0x70, 0xda, 0x12, 0xbd, 0x4f, + 0xc8, 0xe9, 0x91, 0xc7, 0xc7, 0xd6, 0x7b, 0xd0, 0xd1, 0x69, 0x60, 0x28, 0x5d, 0xc4, 0xf4, 0xe3, + 0xa7, 0x6f, 0x51, 0xde, 0x7b, 0x4e, 0xfb, 0x34, 0x07, 0x31, 0xfb, 0x32, 0x5c, 0xba, 0x87, 0x18, + 0xa7, 0x64, 0x5a, 0x74, 0x8c, 0xfd, 0x23, 0x80, 0x83, 0x88, 0x23, 0xfa, 0xc8, 0xf3, 0x11, 0xb3, + 0xde, 0xcc, 0x43, 0x3a, 0x39, 0x5a, 0x1b, 0xaa, 0x76, 0x4f, 0x3a, 0xe1, 0x00, 0x4e, 0x69, 0xec, + 0x21, 0xac, 0x3a, 0x24, 0x11, 0xe1, 0xe8, 0x65, 0x33, 0xd2, 0xeb, 0x5a, 0x7a, 0x9d, 0x44, 0x3a, + 0xab, 0x54, 0xce, 0xd9, 0xfb, 0xa6, 0x84, 0xcd, 0xd8, 0xe9, 0x2d, 0x1a, 0x42, 0x23, 0xe5, 0xab, + 0xa3, 0xca, 0xbc, 0xe8, 0x8c, 0xc4, 0xfe, 0x00, 0xd6, 0x15, 0x27, 0x25, 0xd5, 0xb0, 0x79, 0x19, + 0xb4, 0x28, 0xcd, 0x43, 0xf7, 0x79, 0x34, 0x91, 0x51, 0xe3, 0x32, 0x5c, 0xfa, 0x14, 0x33, 0x9e, + 0x19, 0x6b, 0xfc, 0xb1, 0x0e, 0x3d, 0x31, 0x51, 0xe0, 0x69, 0x7f, 0x04, 0xad, 0xbb, 0xce, 0xd1, + 0x67, 0x08, 0x8f, 0xc6, 0x27, 0x22, 0x7a, 0xfe, 0xb0, 0x08, 0x6b, 0x83, 0x2d, 0xad, 0x6d, 0x6e, + 0xca, 0x69, 0x79, 0x39, 0x3a, 0xfb, 0x63, 0xd8, 0xbc, 0x1b, 0x04, 0xf9, 0xa5, 0x46, 0xeb, 0x37, + 0xa1, 0x11, 0xe5, 0xd8, 0xe5, 0xde, 0xac, 0x02, 0x75, 0x46, 0x64, 0xff, 0x0c, 0xd6, 0xef, 0x47, + 0x13, 0x1c, 0xa1, 0x9d, 0xa3, 0x87, 0x87, 0x28, 0x8d, 0x45, 0x16, 0x54, 0x45, 0xce, 0x26, 0x79, + 0xd4, 0x1d, 0x39, 0x16, 0x97, 0x33, 0x3a, 0x71, 0xfd, 0x38, 0x61, 0xba, 0xd9, 0xb3, 0x1a, 0x9d, + 0xec, 0xc4, 0x09, 0x13, 0x8f, 0x8b, 0x48, 0x2e, 0x48, 0x34, 0x99, 0xca, 0x1b, 0x5a, 0x77, 0x6a, + 0x7e, 0x9c, 0xdc, 0x8f, 0x26, 0x53, 0xfb, 0x07, 0xb2, 0x02, 0x47, 0x28, 0x70, 0xbc, 0x28, 0x20, + 0xe1, 0x3d, 0x74, 0x96, 0x93, 0x90, 0x56, 0x7b, 0x26, 0x12, 0x7d, 0x53, 0x82, 0xd6, 0xdd, 0x11, + 0x8a, 0xf8, 0x3d, 0xc4, 0x3d, 0x3c, 0x91, 0x15, 0xdd, 0x19, 0xa2, 0x0c, 0x93, 0x48, 0x5f, 0x37, + 0x03, 0x8a, 0x82, 0x1c, 0x47, 0x98, 0xbb, 0x81, 0x87, 0x42, 0x12, 0x49, 0x2e, 0x75, 0x71, 0xa2, + 0x30, 0xbf, 0x27, 0x31, 0xd6, 0xab, 0xd0, 0x55, 0xcd, 0x38, 0x77, 0xec, 0x45, 0xc1, 0x44, 0x5c, + 0xf4, 0x8a, 0xbc, 0x9a, 0x1d, 0x85, 0xde, 0xd7, 0x58, 0xeb, 0x35, 0x58, 0xd3, 0xd7, 0x30, 0xa3, + 0xac, 0x4a, 0xca, 0xae, 0xc6, 0x17, 0x48, 0x93, 0x38, 0x26, 0x94, 0x33, 0x97, 0x21, 0xdf, 0x27, + 0x61, 0xac, 0xcb, 0xa1, 0xae, 0xc1, 0x1f, 0x2b, 0xb4, 0x3d, 0x82, 0xf5, 0x3d, 0x61, 0xa7, 0xb6, + 0x24, 0x3b, 0x56, 0x9d, 0x10, 0x85, 0xee, 0xc9, 0x84, 0xf8, 0xa7, 0xae, 0x08, 0x8e, 0xda, 0xc3, + 0x22, 0xe1, 0xda, 0x16, 0xc8, 0x63, 0xfc, 0xb5, 0xac, 0xfc, 0x05, 0xd5, 0x98, 0xf0, 0x78, 0x92, + 0x8c, 0xdc, 0x98, 0x92, 0x13, 0xa4, 0x4d, 0xec, 0x86, 0x28, 0xdc, 0x57, 0xf8, 0x23, 0x81, 0xb6, + 0xff, 0x52, 0x82, 0x8d, 0xa2, 0x24, 0x1d, 0xea, 0x6f, 0xc2, 0x46, 0x51, 0x94, 0x7e, 0xfe, 0x55, + 0x7a, 0xd9, 0xcb, 0x0b, 0x54, 0x89, 0xc0, 0x6d, 0x68, 0xcb, 0x7e, 0xad, 0x1b, 0x28, 0x4e, 0xc5, + 0xa4, 0x27, 0xbf, 0x2f, 0x4e, 0xcb, 0xcb, 0xef, 0xd2, 0x7b, 0x70, 0x45, 0x9b, 0xef, 0xce, 0xab, + 0xad, 0x0e, 0xc4, 0xa6, 0x26, 0x38, 0x9c, 0xd1, 0xfe, 0x53, 0xe8, 0x67, 0xa8, 0xed, 0xa9, 0x44, + 0x66, 0x87, 0x79, 0x7d, 0xc6, 0xd8, 0xbb, 0x41, 0x40, 0xe5, 0x2d, 0xa9, 0x3a, 0x8b, 0xa6, 0xec, + 0x3b, 0x70, 0xf9, 0x18, 0x71, 0xe5, 0x0d, 0x8f, 0xeb, 0x4a, 0x44, 0x31, 0x5b, 0x83, 0xca, 0x31, + 0xf2, 0xa5, 0xf1, 0x15, 0xa7, 0xc2, 0x90, 0x2f, 0x0e, 0xe0, 0x43, 0x86, 0x7c, 0x69, 0x65, 0xc5, + 0xa9, 0x26, 0x0c, 0xf9, 0xf6, 0x9f, 0x4b, 0x50, 0xd3, 0xc1, 0x59, 0x3c, 0x30, 0x01, 0xc5, 0x67, + 0x88, 0xea, 0xa3, 0xa7, 0x21, 0xeb, 0x15, 0xe8, 0xa8, 0x91, 0x4b, 0x62, 0x8e, 0x49, 0x1a, 0xf2, + 0xdb, 0x0a, 0x7b, 0x5f, 0x21, 0x65, 0xf3, 0x4d, 0xb6, 0xbf, 0x74, 0xa5, 0xa9, 0x21, 0x81, 0x7f, + 0xc4, 0xc4, 0x0d, 0x97, 0x21, 0xbe, 0xe1, 0x68, 0x48, 0x1c, 0x75, 0xc3, 0x6f, 0x45, 0xf2, 0x33, + 0xa0, 0x38, 0xea, 0x21, 0x49, 0x22, 0xee, 0xc6, 0x04, 0x47, 0x5c, 0xc7, 0x74, 0x90, 0xa8, 0x23, + 0x81, 0xb1, 0x7f, 0x53, 0x82, 0x55, 0xd5, 0x80, 0x16, 0xb5, 0x6d, 0xfa, 0xb2, 0x96, 0xb1, 0xcc, + 0x52, 0xa4, 0x2c, 0xf5, 0x9a, 0xca, 0xb1, 0xb8, 0xc7, 0x67, 0xa1, 0x7a, 0x1f, 0xb4, 0x6a, 0x67, + 0xa1, 0x7c, 0x18, 0x5e, 0x81, 0x4e, 0xf6, 0x40, 0xcb, 0x79, 0xa5, 0x62, 0x3b, 0xc5, 0x4a, 0xb2, + 0xa5, 0x9a, 0xda, 0x3f, 0x16, 0x25, 0x7d, 0xda, 0x7c, 0x5d, 0x83, 0x4a, 0x92, 0x2a, 0x23, 0x86, + 0x02, 0x33, 0x4a, 0x9f, 0x76, 0x31, 0xb4, 0xae, 0x43, 0xc7, 0x0b, 0x02, 0x2c, 0x96, 0x7b, 0x93, + 0x3d, 0x1c, 0xa4, 0x97, 0xb4, 0x88, 0xb5, 0xff, 0x56, 0x82, 0xee, 0x0e, 0x89, 0xa7, 0x1f, 0xe1, + 0x09, 0xca, 0x45, 0x10, 0xa9, 0xa4, 0x7e, 0xd9, 0xc5, 0x58, 0x64, 0xab, 0x8f, 0xf0, 0x04, 0xa9, + 0xab, 0xa5, 0x76, 0xb6, 0x2e, 0x10, 0xf2, 0x5a, 0x99, 0xc9, 0xb4, 0xed, 0xd6, 0x56, 0x93, 0x87, + 0x24, 0x90, 0x79, 0x79, 0x80, 0xa9, 0x9b, 0x36, 0xd9, 0xda, 0x4e, 0x2d, 0xc0, 0x54, 0x4e, 0x69, + 0x43, 0x56, 0x64, 0x13, 0x35, 0x6f, 0xc8, 0xaa, 0xc2, 0x08, 0x43, 0x36, 0x61, 0x95, 0x3c, 0x7a, + 0xc4, 0x10, 0x97, 0x19, 0x74, 0xc5, 0xd1, 0x50, 0x1a, 0xe6, 0xea, 0xb9, 0x30, 0x77, 0x09, 0xd6, + 0x65, 0xbb, 0xfe, 0x01, 0xf5, 0x7c, 0x1c, 0x8d, 0xcc, 0xf3, 0xb0, 0x01, 0xd6, 0x31, 0x27, 0xf1, + 0x3c, 0x76, 0x0f, 0xf1, 0xfb, 0xf7, 0x0f, 0x77, 0xcf, 0x50, 0xc4, 0x0d, 0xf6, 0x0d, 0xa8, 0x1b, + 0xd4, 0x7f, 0xd3, 0xcb, 0x5c, 0x87, 0xde, 0x1e, 0xe2, 0x87, 0x88, 0x53, 0xec, 0xa7, 0xcf, 0xd1, + 0x35, 0xa8, 0x69, 0x8c, 0xd8, 0xd2, 0x50, 0x0d, 0x4d, 0x9c, 0xd5, 0xe0, 0xad, 0x5f, 0xf7, 0x74, + 0x48, 0xd6, 0xd5, 0xbd, 0xb5, 0x07, 0xdd, 0x99, 0x4f, 0x31, 0x96, 0x6e, 0xf7, 0x2c, 0xfe, 0x42, + 0x33, 0xd8, 0x1c, 0xaa, 0x4f, 0x3b, 0x43, 0xf3, 0x69, 0x67, 0xb8, 0x1b, 0xc6, 0x7c, 0x6a, 0xed, + 0x42, 0xa7, 0xf8, 0xd1, 0xc2, 0x7a, 0xde, 0x64, 0x47, 0x0b, 0x3e, 0x65, 0x2c, 0x65, 0xb3, 0x07, + 0xdd, 0x99, 0xef, 0x17, 0x46, 0x9f, 0xc5, 0x9f, 0x35, 0x96, 0x32, 0xba, 0x03, 0xcd, 0xdc, 0x07, + 0x0b, 0xab, 0xaf, 0x98, 0xcc, 0x7f, 0xc3, 0x58, 0xca, 0x60, 0x07, 0xda, 0x85, 0x6f, 0x08, 0xd6, + 0x40, 0xdb, 0xb3, 0xe0, 0xc3, 0xc2, 0x52, 0x26, 0xdb, 0xd0, 0xcc, 0xb5, 0xf2, 0x8d, 0x16, 0xf3, + 0xdf, 0x0b, 0x06, 0x57, 0x16, 0xcc, 0xe8, 0xc8, 0xbf, 0x07, 0xdd, 0x99, 0xfe, 0xbe, 0x71, 0xc9, + 0xe2, 0xb6, 0xff, 0x52, 0x65, 0x3e, 0x91, 0x5b, 0x94, 0x2b, 0xdf, 0x72, 0x5b, 0x34, 0xdf, 0xcd, + 0x1f, 0xbc, 0xb0, 0x78, 0x52, 0x6b, 0xb5, 0x0b, 0x9d, 0x62, 0x23, 0xdf, 0x30, 0x5b, 0xd8, 0xde, + 0xbf, 0x78, 0xbf, 0x0b, 0x3d, 0xfd, 0x6c, 0xbf, 0x17, 0xb5, 0xfa, 0x97, 0x32, 0xba, 0x0b, 0xa0, + 0x8b, 0xb5, 0x00, 0x47, 0xa9, 0xa3, 0xe7, 0x8a, 0xc4, 0xd4, 0xd1, 0x0b, 0x0a, 0xbb, 0x3b, 0x00, + 0xaa, 0xc6, 0x0a, 0x48, 0xc2, 0xad, 0xcb, 0x46, 0x8d, 0x99, 0xc2, 0x6e, 0xd0, 0x9f, 0x9f, 0x98, + 0x63, 0x80, 0x28, 0x7d, 0x1a, 0x06, 0x1f, 0x02, 0x64, 0xb5, 0x9b, 0x61, 0x30, 0x57, 0xcd, 0x5d, + 0xe0, 0x83, 0x56, 0xbe, 0x52, 0xb3, 0xb4, 0xad, 0x0b, 0xaa, 0xb7, 0x0b, 0x58, 0x74, 0x67, 0x32, + 0xf1, 0xe2, 0x61, 0x9b, 0x4d, 0xd0, 0x07, 0x73, 0xd9, 0xb8, 0x75, 0x1b, 0x5a, 0xf9, 0x14, 0xdc, + 0x68, 0xb1, 0x20, 0x2d, 0x1f, 0x14, 0xd2, 0x70, 0xeb, 0x0e, 0x74, 0x8a, 0xe9, 0xb7, 0x39, 0x52, + 0x0b, 0x93, 0xf2, 0x81, 0x6e, 0x2e, 0xe5, 0xc8, 0xdf, 0x06, 0xc8, 0xd2, 0x74, 0xe3, 0xbe, 0xb9, + 0xc4, 0x7d, 0x46, 0xea, 0x1e, 0x74, 0x67, 0xd2, 0x6f, 0x63, 0xf1, 0xe2, 0xac, 0xfc, 0x22, 0xef, + 0xe7, 0xdf, 0x01, 0x63, 0xf7, 0x82, 0xb7, 0xe1, 0xa2, 0xa0, 0x95, 0x7b, 0x33, 0xcc, 0x29, 0x9e, + 0x7f, 0x46, 0x96, 0x32, 0x78, 0x07, 0x20, 0x7b, 0x19, 0x8c, 0x07, 0xe6, 0xde, 0x8a, 0x41, 0xdb, + 0x34, 0xff, 0x14, 0xdd, 0x0e, 0xb4, 0x0b, 0xf5, 0xb1, 0x09, 0x75, 0x8b, 0x8a, 0xe6, 0x8b, 0x1e, + 0x80, 0x62, 0x31, 0x69, 0x76, 0x6f, 0x61, 0x89, 0x79, 0x91, 0x17, 0xf3, 0x15, 0x8c, 0xf1, 0xe2, + 0x82, 0xaa, 0xe6, 0x3b, 0x62, 0x4a, 0xbe, 0x4a, 0xc9, 0xc5, 0x94, 0x05, 0xc5, 0xcb, 0x52, 0x46, + 0xfb, 0xd0, 0xdd, 0x33, 0x09, 0xa8, 0x4e, 0x8e, 0xb5, 0x3a, 0x0b, 0x8a, 0x81, 0xc1, 0x60, 0xd1, + 0x94, 0xbe, 0xd8, 0x9f, 0x40, 0x6f, 0x2e, 0x31, 0xb6, 0xb6, 0xd2, 0x16, 0xec, 0xc2, 0x8c, 0x79, + 0xa9, 0x5a, 0x07, 0xb0, 0x36, 0x9b, 0x17, 0x5b, 0x2f, 0xea, 0xa3, 0xb2, 0x38, 0x5f, 0x5e, 0xca, + 0xea, 0x3d, 0xa8, 0x9b, 0x3c, 0xcc, 0xd2, 0xad, 0xee, 0x99, 0xbc, 0x6c, 0xe9, 0xd2, 0xdb, 0xd0, + 0xcc, 0x65, 0x32, 0xe6, 0xac, 0xce, 0x27, 0x37, 0x03, 0xdd, 0x99, 0x36, 0xe8, 0xed, 0xf3, 0x6f, + 0xbe, 0xdd, 0x7a, 0xee, 0x1f, 0xdf, 0x6e, 0x3d, 0xf7, 0xab, 0x27, 0x5b, 0xa5, 0x6f, 0x9e, 0x6c, + 0x95, 0xfe, 0xfe, 0x64, 0xab, 0xf4, 0xaf, 0x27, 0x5b, 0xa5, 0x9f, 0xfc, 0xfc, 0x7f, 0xfc, 0x9b, + 0x0a, 0x4d, 0x22, 0x8e, 0x43, 0x74, 0xf3, 0x0c, 0x53, 0x9e, 0x9b, 0x8a, 0x4f, 0x47, 0x73, 0xff, + 0x60, 0x11, 0x2a, 0x9c, 0xac, 0x4a, 0xf8, 0xed, 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0x22, 0x03, + 0xd8, 0x19, 0x0f, 0x23, 0x00, 0x00, } func (m *CreateContainerRequest) Marshal() (dAtA []byte, err error) { diff --git a/src/runtime/virtcontainers/pkg/agent/protocols/grpc/oci.pb.go b/src/runtime/virtcontainers/pkg/agent/protocols/grpc/oci.pb.go index 2dc8fd757f62..6b5ca0fe48be 100644 --- a/src/runtime/virtcontainers/pkg/agent/protocols/grpc/oci.pb.go +++ b/src/runtime/virtcontainers/pkg/agent/protocols/grpc/oci.pb.go @@ -29,25 +29,25 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type Spec struct { // Version of the Open Container Initiative Runtime Specification with which the bundle complies. - Version string `protobuf:"bytes,1,opt,name=Version,proto3" json:"Version,omitempty"` + Version string `protobuf:"bytes,1,opt,name=Version,json=version,proto3" json:"Version,omitempty"` // Process configures the container process. - Process *Process `protobuf:"bytes,2,opt,name=Process,proto3" json:"Process,omitempty"` + Process *Process `protobuf:"bytes,2,opt,name=Process,json=process,proto3" json:"Process,omitempty"` // Root configures the container's root filesystem. - Root *Root `protobuf:"bytes,3,opt,name=Root,proto3" json:"Root,omitempty"` + Root *Root `protobuf:"bytes,3,opt,name=Root,json=root,proto3" json:"Root,omitempty"` // Hostname configures the container's hostname. - Hostname string `protobuf:"bytes,4,opt,name=Hostname,proto3" json:"Hostname,omitempty"` + Hostname string `protobuf:"bytes,4,opt,name=Hostname,json=hostname,proto3" json:"Hostname,omitempty"` // Mounts configures additional mounts (on top of Root). - Mounts []Mount `protobuf:"bytes,5,rep,name=Mounts,proto3" json:"Mounts"` + Mounts []Mount `protobuf:"bytes,5,rep,name=Mounts,json=mounts,proto3" json:"Mounts"` // Hooks configures callbacks for container lifecycle events. - Hooks *Hooks `protobuf:"bytes,6,opt,name=Hooks,proto3" json:"Hooks,omitempty"` + Hooks *Hooks `protobuf:"bytes,6,opt,name=Hooks,json=hooks,proto3" json:"Hooks,omitempty"` // Annotations contains arbitrary metadata for the container. - Annotations map[string]string `protobuf:"bytes,7,rep,name=Annotations,proto3" json:"Annotations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Annotations map[string]string `protobuf:"bytes,7,rep,name=Annotations,json=annotations,proto3" json:"Annotations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // Linux is platform-specific configuration for Linux based containers. - Linux *Linux `protobuf:"bytes,8,opt,name=Linux,proto3" json:"Linux,omitempty"` + Linux *Linux `protobuf:"bytes,8,opt,name=Linux,json=linux,proto3" json:"Linux,omitempty"` // Solaris is platform-specific configuration for Solaris based containers. - Solaris *Solaris `protobuf:"bytes,9,opt,name=Solaris,proto3" json:"Solaris,omitempty"` + Solaris *Solaris `protobuf:"bytes,9,opt,name=Solaris,json=solaris,proto3" json:"Solaris,omitempty"` // Windows is platform-specific configuration for Windows based containers. - Windows *Windows `protobuf:"bytes,10,opt,name=Windows,proto3" json:"Windows,omitempty"` + Windows *Windows `protobuf:"bytes,10,opt,name=Windows,json=windows,proto3" json:"Windows,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -87,30 +87,30 @@ var xxx_messageInfo_Spec proto.InternalMessageInfo type Process struct { // Terminal creates an interactive terminal for the container. - Terminal bool `protobuf:"varint,1,opt,name=Terminal,proto3" json:"Terminal,omitempty"` + Terminal bool `protobuf:"varint,1,opt,name=Terminal,json=terminal,proto3" json:"Terminal,omitempty"` // ConsoleSize specifies the size of the console. - ConsoleSize *Box `protobuf:"bytes,2,opt,name=ConsoleSize,proto3" json:"ConsoleSize,omitempty"` + ConsoleSize *Box `protobuf:"bytes,2,opt,name=ConsoleSize,json=consoleSize,proto3" json:"ConsoleSize,omitempty"` // User specifies user information for the process. - User User `protobuf:"bytes,3,opt,name=User,proto3" json:"User"` + User User `protobuf:"bytes,3,opt,name=User,json=user,proto3" json:"User"` // Args specifies the binary and arguments for the application to execute. - Args []string `protobuf:"bytes,4,rep,name=Args,proto3" json:"Args,omitempty"` + Args []string `protobuf:"bytes,4,rep,name=Args,json=args,proto3" json:"Args,omitempty"` // Env populates the process environment for the process. - Env []string `protobuf:"bytes,5,rep,name=Env,proto3" json:"Env,omitempty"` + Env []string `protobuf:"bytes,5,rep,name=Env,json=env,proto3" json:"Env,omitempty"` // Cwd is the current working directory for the process and must be // relative to the container's root. - Cwd string `protobuf:"bytes,6,opt,name=Cwd,proto3" json:"Cwd,omitempty"` + Cwd string `protobuf:"bytes,6,opt,name=Cwd,json=cwd,proto3" json:"Cwd,omitempty"` // Capabilities are Linux capabilities that are kept for the process. - Capabilities *LinuxCapabilities `protobuf:"bytes,7,opt,name=Capabilities,proto3" json:"Capabilities,omitempty"` + Capabilities *LinuxCapabilities `protobuf:"bytes,7,opt,name=Capabilities,json=capabilities,proto3" json:"Capabilities,omitempty"` // Rlimits specifies rlimit options to apply to the process. - Rlimits []POSIXRlimit `protobuf:"bytes,8,rep,name=Rlimits,proto3" json:"Rlimits"` + Rlimits []POSIXRlimit `protobuf:"bytes,8,rep,name=Rlimits,json=rlimits,proto3" json:"Rlimits"` // NoNewPrivileges controls whether additional privileges could be gained by processes in the container. - NoNewPrivileges bool `protobuf:"varint,9,opt,name=NoNewPrivileges,proto3" json:"NoNewPrivileges,omitempty"` + NoNewPrivileges bool `protobuf:"varint,9,opt,name=NoNewPrivileges,json=noNewPrivileges,proto3" json:"NoNewPrivileges,omitempty"` // ApparmorProfile specifies the apparmor profile for the container. - ApparmorProfile string `protobuf:"bytes,10,opt,name=ApparmorProfile,proto3" json:"ApparmorProfile,omitempty"` + ApparmorProfile string `protobuf:"bytes,10,opt,name=ApparmorProfile,json=apparmorProfile,proto3" json:"ApparmorProfile,omitempty"` // Specify an oom_score_adj for the container. - OOMScoreAdj int64 `protobuf:"varint,11,opt,name=OOMScoreAdj,proto3" json:"OOMScoreAdj,omitempty"` + OOMScoreAdj int64 `protobuf:"varint,11,opt,name=OOMScoreAdj,json=oOMScoreAdj,proto3" json:"OOMScoreAdj,omitempty"` // SelinuxLabel specifies the selinux context that the container process is run as. - SelinuxLabel string `protobuf:"bytes,12,opt,name=SelinuxLabel,proto3" json:"SelinuxLabel,omitempty"` + SelinuxLabel string `protobuf:"bytes,12,opt,name=SelinuxLabel,json=selinuxLabel,proto3" json:"SelinuxLabel,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -150,9 +150,9 @@ var xxx_messageInfo_Process proto.InternalMessageInfo type Box struct { // Height is the vertical dimension of a box. - Height uint32 `protobuf:"varint,1,opt,name=Height,proto3" json:"Height,omitempty"` + Height uint32 `protobuf:"varint,1,opt,name=Height,json=height,proto3" json:"Height,omitempty"` // Width is the horizontal dimension of a box. - Width uint32 `protobuf:"varint,2,opt,name=Width,proto3" json:"Width,omitempty"` + Width uint32 `protobuf:"varint,2,opt,name=Width,json=width,proto3" json:"Width,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -192,13 +192,13 @@ var xxx_messageInfo_Box proto.InternalMessageInfo type User struct { // UID is the user id. - UID uint32 `protobuf:"varint,1,opt,name=UID,proto3" json:"UID,omitempty"` + UID uint32 `protobuf:"varint,1,opt,name=UID,json=uID,proto3" json:"UID,omitempty"` // GID is the group id. - GID uint32 `protobuf:"varint,2,opt,name=GID,proto3" json:"GID,omitempty"` + GID uint32 `protobuf:"varint,2,opt,name=GID,json=gID,proto3" json:"GID,omitempty"` // AdditionalGids are additional group ids set for the container's process. - AdditionalGids []uint32 `protobuf:"varint,3,rep,packed,name=AdditionalGids,proto3" json:"AdditionalGids,omitempty"` + AdditionalGids []uint32 `protobuf:"varint,3,rep,packed,name=AdditionalGids,json=additionalGids,proto3" json:"AdditionalGids,omitempty"` // Username is the user name. - Username string `protobuf:"bytes,4,opt,name=Username,proto3" json:"Username,omitempty"` + Username string `protobuf:"bytes,4,opt,name=Username,json=username,proto3" json:"Username,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -238,15 +238,15 @@ var xxx_messageInfo_User proto.InternalMessageInfo type LinuxCapabilities struct { // Bounding is the set of capabilities checked by the kernel. - Bounding []string `protobuf:"bytes,1,rep,name=Bounding,proto3" json:"Bounding,omitempty"` + Bounding []string `protobuf:"bytes,1,rep,name=Bounding,json=bounding,proto3" json:"Bounding,omitempty"` // Effective is the set of capabilities checked by the kernel. - Effective []string `protobuf:"bytes,2,rep,name=Effective,proto3" json:"Effective,omitempty"` + Effective []string `protobuf:"bytes,2,rep,name=Effective,json=effective,proto3" json:"Effective,omitempty"` // Inheritable is the capabilities preserved across execve. - Inheritable []string `protobuf:"bytes,3,rep,name=Inheritable,proto3" json:"Inheritable,omitempty"` + Inheritable []string `protobuf:"bytes,3,rep,name=Inheritable,json=inheritable,proto3" json:"Inheritable,omitempty"` // Permitted is the limiting superset for effective capabilities. - Permitted []string `protobuf:"bytes,4,rep,name=Permitted,proto3" json:"Permitted,omitempty"` + Permitted []string `protobuf:"bytes,4,rep,name=Permitted,json=permitted,proto3" json:"Permitted,omitempty"` // Ambient is the ambient set of capabilities that are kept. - Ambient []string `protobuf:"bytes,5,rep,name=Ambient,proto3" json:"Ambient,omitempty"` + Ambient []string `protobuf:"bytes,5,rep,name=Ambient,json=ambient,proto3" json:"Ambient,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -286,11 +286,11 @@ var xxx_messageInfo_LinuxCapabilities proto.InternalMessageInfo type POSIXRlimit struct { // Type of the rlimit to set - Type string `protobuf:"bytes,1,opt,name=Type,proto3" json:"Type,omitempty"` + Type string `protobuf:"bytes,1,opt,name=Type,json=type,proto3" json:"Type,omitempty"` // Hard is the hard limit for the specified type - Hard uint64 `protobuf:"varint,2,opt,name=Hard,proto3" json:"Hard,omitempty"` + Hard uint64 `protobuf:"varint,2,opt,name=Hard,json=hard,proto3" json:"Hard,omitempty"` // Soft is the soft limit for the specified type - Soft uint64 `protobuf:"varint,3,opt,name=Soft,proto3" json:"Soft,omitempty"` + Soft uint64 `protobuf:"varint,3,opt,name=Soft,json=soft,proto3" json:"Soft,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -377,9 +377,9 @@ var xxx_messageInfo_Mount proto.InternalMessageInfo type Root struct { // Path is the absolute path to the container's root filesystem. - Path string `protobuf:"bytes,1,opt,name=Path,proto3" json:"Path,omitempty"` + Path string `protobuf:"bytes,1,opt,name=Path,json=path,proto3" json:"Path,omitempty"` // Readonly makes the root filesystem for the container readonly before the process is executed. - Readonly bool `protobuf:"varint,2,opt,name=Readonly,proto3" json:"Readonly,omitempty"` + Readonly bool `protobuf:"varint,2,opt,name=Readonly,json=readonly,proto3" json:"Readonly,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -419,11 +419,11 @@ var xxx_messageInfo_Root proto.InternalMessageInfo type Hooks struct { // Prestart is a list of hooks to be run before the container process is executed. - Prestart []Hook `protobuf:"bytes,1,rep,name=Prestart,proto3" json:"Prestart"` + Prestart []Hook `protobuf:"bytes,1,rep,name=Prestart,json=prestart,proto3" json:"Prestart"` // Poststart is a list of hooks to be run after the container process is started. - Poststart []Hook `protobuf:"bytes,2,rep,name=Poststart,proto3" json:"Poststart"` + Poststart []Hook `protobuf:"bytes,2,rep,name=Poststart,json=poststart,proto3" json:"Poststart"` // Poststop is a list of hooks to be run after the container process exits. - Poststop []Hook `protobuf:"bytes,3,rep,name=Poststop,proto3" json:"Poststop"` + Poststop []Hook `protobuf:"bytes,3,rep,name=Poststop,json=poststop,proto3" json:"Poststop"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -462,10 +462,10 @@ func (m *Hooks) XXX_DiscardUnknown() { var xxx_messageInfo_Hooks proto.InternalMessageInfo type Hook struct { - Path string `protobuf:"bytes,1,opt,name=Path,proto3" json:"Path,omitempty"` - Args []string `protobuf:"bytes,2,rep,name=Args,proto3" json:"Args,omitempty"` - Env []string `protobuf:"bytes,3,rep,name=Env,proto3" json:"Env,omitempty"` - Timeout int64 `protobuf:"varint,4,opt,name=Timeout,proto3" json:"Timeout,omitempty"` + Path string `protobuf:"bytes,1,opt,name=Path,json=path,proto3" json:"Path,omitempty"` + Args []string `protobuf:"bytes,2,rep,name=Args,json=args,proto3" json:"Args,omitempty"` + Env []string `protobuf:"bytes,3,rep,name=Env,json=env,proto3" json:"Env,omitempty"` + Timeout int64 `protobuf:"varint,4,opt,name=Timeout,json=timeout,proto3" json:"Timeout,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -505,35 +505,35 @@ var xxx_messageInfo_Hook proto.InternalMessageInfo type Linux struct { // UIDMapping specifies user mappings for supporting user namespaces. - UIDMappings []LinuxIDMapping `protobuf:"bytes,1,rep,name=UIDMappings,proto3" json:"UIDMappings"` + UIDMappings []LinuxIDMapping `protobuf:"bytes,1,rep,name=UIDMappings,json=uIDMappings,proto3" json:"UIDMappings"` // GIDMapping specifies group mappings for supporting user namespaces. - GIDMappings []LinuxIDMapping `protobuf:"bytes,2,rep,name=GIDMappings,proto3" json:"GIDMappings"` + GIDMappings []LinuxIDMapping `protobuf:"bytes,2,rep,name=GIDMappings,json=gIDMappings,proto3" json:"GIDMappings"` // Sysctl are a set of key value pairs that are set for the container on start - Sysctl map[string]string `protobuf:"bytes,3,rep,name=Sysctl,proto3" json:"Sysctl,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Sysctl map[string]string `protobuf:"bytes,3,rep,name=Sysctl,json=sysctl,proto3" json:"Sysctl,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // Resources contain cgroup information for handling resource constraints // for the container - Resources *LinuxResources `protobuf:"bytes,4,opt,name=Resources,proto3" json:"Resources,omitempty"` + Resources *LinuxResources `protobuf:"bytes,4,opt,name=Resources,json=resources,proto3" json:"Resources,omitempty"` // CgroupsPath specifies the path to cgroups that are created and/or joined by the container. // The path is expected to be relative to the cgroups mountpoint. // If resources are specified, the cgroups at CgroupsPath will be updated based on resources. - CgroupsPath string `protobuf:"bytes,5,opt,name=CgroupsPath,proto3" json:"CgroupsPath,omitempty"` + CgroupsPath string `protobuf:"bytes,5,opt,name=CgroupsPath,json=cgroupsPath,proto3" json:"CgroupsPath,omitempty"` // Namespaces contains the namespaces that are created and/or joined by the container - Namespaces []LinuxNamespace `protobuf:"bytes,6,rep,name=Namespaces,proto3" json:"Namespaces"` + Namespaces []LinuxNamespace `protobuf:"bytes,6,rep,name=Namespaces,json=namespaces,proto3" json:"Namespaces"` // Devices are a list of device nodes that are created for the container - Devices []LinuxDevice `protobuf:"bytes,7,rep,name=Devices,proto3" json:"Devices"` + Devices []LinuxDevice `protobuf:"bytes,7,rep,name=Devices,json=devices,proto3" json:"Devices"` // Seccomp specifies the seccomp security settings for the container. - Seccomp *LinuxSeccomp `protobuf:"bytes,8,opt,name=Seccomp,proto3" json:"Seccomp,omitempty"` + Seccomp *LinuxSeccomp `protobuf:"bytes,8,opt,name=Seccomp,json=seccomp,proto3" json:"Seccomp,omitempty"` // RootfsPropagation is the rootfs mount propagation mode for the container. - RootfsPropagation string `protobuf:"bytes,9,opt,name=RootfsPropagation,proto3" json:"RootfsPropagation,omitempty"` + RootfsPropagation string `protobuf:"bytes,9,opt,name=RootfsPropagation,json=rootfsPropagation,proto3" json:"RootfsPropagation,omitempty"` // MaskedPaths masks over the provided paths inside the container. - MaskedPaths []string `protobuf:"bytes,10,rep,name=MaskedPaths,proto3" json:"MaskedPaths,omitempty"` + MaskedPaths []string `protobuf:"bytes,10,rep,name=MaskedPaths,json=maskedPaths,proto3" json:"MaskedPaths,omitempty"` // ReadonlyPaths sets the provided paths as RO inside the container. - ReadonlyPaths []string `protobuf:"bytes,11,rep,name=ReadonlyPaths,proto3" json:"ReadonlyPaths,omitempty"` + ReadonlyPaths []string `protobuf:"bytes,11,rep,name=ReadonlyPaths,json=readonlyPaths,proto3" json:"ReadonlyPaths,omitempty"` // MountLabel specifies the selinux context for the mounts in the container. - MountLabel string `protobuf:"bytes,12,opt,name=MountLabel,proto3" json:"MountLabel,omitempty"` + MountLabel string `protobuf:"bytes,12,opt,name=MountLabel,json=mountLabel,proto3" json:"MountLabel,omitempty"` // IntelRdt contains Intel Resource Director Technology (RDT) information // for handling resource constraints (e.g., L3 cache) for the container - IntelRdt *LinuxIntelRdt `protobuf:"bytes,13,opt,name=IntelRdt,proto3" json:"IntelRdt,omitempty"` + IntelRdt *LinuxIntelRdt `protobuf:"bytes,13,opt,name=IntelRdt,json=intelRdt,proto3" json:"IntelRdt,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -653,11 +653,11 @@ var xxx_messageInfo_Solaris proto.InternalMessageInfo type LinuxIDMapping struct { // HostID is the starting UID/GID on the host to be mapped to 'ContainerID' - HostID uint32 `protobuf:"varint,1,opt,name=HostID,proto3" json:"HostID,omitempty"` + HostID uint32 `protobuf:"varint,1,opt,name=HostID,json=hostID,proto3" json:"HostID,omitempty"` // ContainerID is the starting UID/GID in the container - ContainerID uint32 `protobuf:"varint,2,opt,name=ContainerID,proto3" json:"ContainerID,omitempty"` + ContainerID uint32 `protobuf:"varint,2,opt,name=ContainerID,json=containerID,proto3" json:"ContainerID,omitempty"` // Size is the number of IDs to be mapped - Size_ uint32 `protobuf:"varint,3,opt,name=Size,proto3" json:"Size,omitempty"` + Size_ uint32 `protobuf:"varint,3,opt,name=Size,json=size,proto3" json:"Size,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -697,10 +697,10 @@ var xxx_messageInfo_LinuxIDMapping proto.InternalMessageInfo type LinuxNamespace struct { // Type is the type of namespace - Type string `protobuf:"bytes,1,opt,name=Type,proto3" json:"Type,omitempty"` + Type string `protobuf:"bytes,1,opt,name=Type,json=type,proto3" json:"Type,omitempty"` // Path is a path to an existing namespace persisted on disk that can be joined // and is of the same type - Path string `protobuf:"bytes,2,opt,name=Path,proto3" json:"Path,omitempty"` + Path string `protobuf:"bytes,2,opt,name=Path,json=path,proto3" json:"Path,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -740,19 +740,19 @@ var xxx_messageInfo_LinuxNamespace proto.InternalMessageInfo type LinuxDevice struct { // Path to the device. - Path string `protobuf:"bytes,1,opt,name=Path,proto3" json:"Path,omitempty"` + Path string `protobuf:"bytes,1,opt,name=Path,json=path,proto3" json:"Path,omitempty"` // Device type, block, char, etc. - Type string `protobuf:"bytes,2,opt,name=Type,proto3" json:"Type,omitempty"` + Type string `protobuf:"bytes,2,opt,name=Type,json=type,proto3" json:"Type,omitempty"` // Major is the device's major number. - Major int64 `protobuf:"varint,3,opt,name=Major,proto3" json:"Major,omitempty"` + Major int64 `protobuf:"varint,3,opt,name=Major,json=major,proto3" json:"Major,omitempty"` // Minor is the device's minor number. - Minor int64 `protobuf:"varint,4,opt,name=Minor,proto3" json:"Minor,omitempty"` + Minor int64 `protobuf:"varint,4,opt,name=Minor,json=minor,proto3" json:"Minor,omitempty"` // FileMode permission bits for the device. - FileMode uint32 `protobuf:"varint,5,opt,name=FileMode,proto3" json:"FileMode,omitempty"` + FileMode uint32 `protobuf:"varint,5,opt,name=FileMode,json=fileMode,proto3" json:"FileMode,omitempty"` // UID of the device. - UID uint32 `protobuf:"varint,6,opt,name=UID,proto3" json:"UID,omitempty"` + UID uint32 `protobuf:"varint,6,opt,name=UID,json=uID,proto3" json:"UID,omitempty"` // Gid of the device. - GID uint32 `protobuf:"varint,7,opt,name=GID,proto3" json:"GID,omitempty"` + GID uint32 `protobuf:"varint,7,opt,name=GID,json=gID,proto3" json:"GID,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -792,19 +792,19 @@ var xxx_messageInfo_LinuxDevice proto.InternalMessageInfo type LinuxResources struct { // Devices configures the device whitelist. - Devices []LinuxDeviceCgroup `protobuf:"bytes,1,rep,name=Devices,proto3" json:"Devices"` + Devices []LinuxDeviceCgroup `protobuf:"bytes,1,rep,name=Devices,json=devices,proto3" json:"Devices"` // Memory restriction configuration - Memory *LinuxMemory `protobuf:"bytes,2,opt,name=Memory,proto3" json:"Memory,omitempty"` + Memory *LinuxMemory `protobuf:"bytes,2,opt,name=Memory,json=memory,proto3" json:"Memory,omitempty"` // CPU resource restriction configuration - CPU *LinuxCPU `protobuf:"bytes,3,opt,name=CPU,proto3" json:"CPU,omitempty"` + CPU *LinuxCPU `protobuf:"bytes,3,opt,name=CPU,json=cPU,proto3" json:"CPU,omitempty"` // Task resource restriction configuration. - Pids *LinuxPids `protobuf:"bytes,4,opt,name=Pids,proto3" json:"Pids,omitempty"` + Pids *LinuxPids `protobuf:"bytes,4,opt,name=Pids,json=pids,proto3" json:"Pids,omitempty"` // BlockIO restriction configuration - BlockIO *LinuxBlockIO `protobuf:"bytes,5,opt,name=BlockIO,proto3" json:"BlockIO,omitempty"` + BlockIO *LinuxBlockIO `protobuf:"bytes,5,opt,name=BlockIO,json=blockIO,proto3" json:"BlockIO,omitempty"` // Hugetlb limit (in bytes) - HugepageLimits []LinuxHugepageLimit `protobuf:"bytes,6,rep,name=HugepageLimits,proto3" json:"HugepageLimits"` + HugepageLimits []LinuxHugepageLimit `protobuf:"bytes,6,rep,name=HugepageLimits,json=hugepageLimits,proto3" json:"HugepageLimits"` // Network restriction configuration - Network *LinuxNetwork `protobuf:"bytes,7,opt,name=Network,proto3" json:"Network,omitempty"` + Network *LinuxNetwork `protobuf:"bytes,7,opt,name=Network,json=network,proto3" json:"Network,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -844,19 +844,19 @@ var xxx_messageInfo_LinuxResources proto.InternalMessageInfo type LinuxMemory struct { // Memory limit (in bytes). - Limit int64 `protobuf:"varint,1,opt,name=Limit,proto3" json:"Limit,omitempty"` + Limit int64 `protobuf:"varint,1,opt,name=Limit,json=limit,proto3" json:"Limit,omitempty"` // Memory reservation or soft_limit (in bytes). - Reservation int64 `protobuf:"varint,2,opt,name=Reservation,proto3" json:"Reservation,omitempty"` + Reservation int64 `protobuf:"varint,2,opt,name=Reservation,json=reservation,proto3" json:"Reservation,omitempty"` // Total memory limit (memory + swap). - Swap int64 `protobuf:"varint,3,opt,name=Swap,proto3" json:"Swap,omitempty"` + Swap int64 `protobuf:"varint,3,opt,name=Swap,json=swap,proto3" json:"Swap,omitempty"` // Kernel memory limit (in bytes). - Kernel int64 `protobuf:"varint,4,opt,name=Kernel,proto3" json:"Kernel,omitempty"` + Kernel int64 `protobuf:"varint,4,opt,name=Kernel,json=kernel,proto3" json:"Kernel,omitempty"` // Kernel memory limit for tcp (in bytes) - KernelTCP int64 `protobuf:"varint,5,opt,name=KernelTCP,proto3" json:"KernelTCP,omitempty"` + KernelTCP int64 `protobuf:"varint,5,opt,name=KernelTCP,json=kernelTCP,proto3" json:"KernelTCP,omitempty"` // How aggressive the kernel will swap memory pages. - Swappiness uint64 `protobuf:"varint,6,opt,name=Swappiness,proto3" json:"Swappiness,omitempty"` + Swappiness uint64 `protobuf:"varint,6,opt,name=Swappiness,json=swappiness,proto3" json:"Swappiness,omitempty"` // DisableOOMKiller disables the OOM killer for out of memory conditions - DisableOOMKiller bool `protobuf:"varint,7,opt,name=DisableOOMKiller,proto3" json:"DisableOOMKiller,omitempty"` + DisableOOMKiller bool `protobuf:"varint,7,opt,name=DisableOOMKiller,json=disableOOMKiller,proto3" json:"DisableOOMKiller,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -896,19 +896,19 @@ var xxx_messageInfo_LinuxMemory proto.InternalMessageInfo type LinuxCPU struct { // CPU shares (relative weight (ratio) vs. other cgroups with cpu shares). - Shares uint64 `protobuf:"varint,1,opt,name=Shares,proto3" json:"Shares,omitempty"` + Shares uint64 `protobuf:"varint,1,opt,name=Shares,json=shares,proto3" json:"Shares,omitempty"` // CPU hardcap limit (in usecs). Allowed cpu time in a given period. - Quota int64 `protobuf:"varint,2,opt,name=Quota,proto3" json:"Quota,omitempty"` + Quota int64 `protobuf:"varint,2,opt,name=Quota,json=quota,proto3" json:"Quota,omitempty"` // CPU period to be used for hardcapping (in usecs). - Period uint64 `protobuf:"varint,3,opt,name=Period,proto3" json:"Period,omitempty"` + Period uint64 `protobuf:"varint,3,opt,name=Period,json=period,proto3" json:"Period,omitempty"` // How much time realtime scheduling may use (in usecs). - RealtimeRuntime int64 `protobuf:"varint,4,opt,name=RealtimeRuntime,proto3" json:"RealtimeRuntime,omitempty"` + RealtimeRuntime int64 `protobuf:"varint,4,opt,name=RealtimeRuntime,json=realtimeRuntime,proto3" json:"RealtimeRuntime,omitempty"` // CPU period to be used for realtime scheduling (in usecs). - RealtimePeriod uint64 `protobuf:"varint,5,opt,name=RealtimePeriod,proto3" json:"RealtimePeriod,omitempty"` + RealtimePeriod uint64 `protobuf:"varint,5,opt,name=RealtimePeriod,json=realtimePeriod,proto3" json:"RealtimePeriod,omitempty"` // CPUs to use within the cpuset. Default is to use any CPU available. - Cpus string `protobuf:"bytes,6,opt,name=Cpus,proto3" json:"Cpus,omitempty"` + Cpus string `protobuf:"bytes,6,opt,name=Cpus,json=cpus,proto3" json:"Cpus,omitempty"` // List of memory nodes in the cpuset. Default is to use any available memory node. - Mems string `protobuf:"bytes,7,opt,name=Mems,proto3" json:"Mems,omitempty"` + Mems string `protobuf:"bytes,7,opt,name=Mems,json=mems,proto3" json:"Mems,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -948,13 +948,13 @@ var xxx_messageInfo_LinuxCPU proto.InternalMessageInfo type LinuxWeightDevice struct { // Major is the device's major number. - Major int64 `protobuf:"varint,1,opt,name=Major,proto3" json:"Major,omitempty"` + Major int64 `protobuf:"varint,1,opt,name=Major,json=major,proto3" json:"Major,omitempty"` // Minor is the device's minor number. - Minor int64 `protobuf:"varint,2,opt,name=Minor,proto3" json:"Minor,omitempty"` + Minor int64 `protobuf:"varint,2,opt,name=Minor,json=minor,proto3" json:"Minor,omitempty"` // Weight is the bandwidth rate for the device. - Weight uint32 `protobuf:"varint,3,opt,name=Weight,proto3" json:"Weight,omitempty"` + Weight uint32 `protobuf:"varint,3,opt,name=Weight,json=weight,proto3" json:"Weight,omitempty"` // LeafWeight is the bandwidth rate for the device while competing with the cgroup's child cgroups, CFQ scheduler only - LeafWeight uint32 `protobuf:"varint,4,opt,name=LeafWeight,proto3" json:"LeafWeight,omitempty"` + LeafWeight uint32 `protobuf:"varint,4,opt,name=LeafWeight,json=leafWeight,proto3" json:"LeafWeight,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -994,11 +994,11 @@ var xxx_messageInfo_LinuxWeightDevice proto.InternalMessageInfo type LinuxThrottleDevice struct { // Major is the device's major number. - Major int64 `protobuf:"varint,1,opt,name=Major,proto3" json:"Major,omitempty"` + Major int64 `protobuf:"varint,1,opt,name=Major,json=major,proto3" json:"Major,omitempty"` // Minor is the device's minor number. - Minor int64 `protobuf:"varint,2,opt,name=Minor,proto3" json:"Minor,omitempty"` + Minor int64 `protobuf:"varint,2,opt,name=Minor,json=minor,proto3" json:"Minor,omitempty"` // Rate is the IO rate limit per cgroup per device - Rate uint64 `protobuf:"varint,3,opt,name=Rate,proto3" json:"Rate,omitempty"` + Rate uint64 `protobuf:"varint,3,opt,name=Rate,json=rate,proto3" json:"Rate,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1038,19 +1038,19 @@ var xxx_messageInfo_LinuxThrottleDevice proto.InternalMessageInfo type LinuxBlockIO struct { // Specifies per cgroup weight - Weight uint32 `protobuf:"varint,1,opt,name=Weight,proto3" json:"Weight,omitempty"` + Weight uint32 `protobuf:"varint,1,opt,name=Weight,json=weight,proto3" json:"Weight,omitempty"` // Specifies tasks' weight in the given cgroup while competing with the cgroup's child cgroups, CFQ scheduler only - LeafWeight uint32 `protobuf:"varint,2,opt,name=LeafWeight,proto3" json:"LeafWeight,omitempty"` + LeafWeight uint32 `protobuf:"varint,2,opt,name=LeafWeight,json=leafWeight,proto3" json:"LeafWeight,omitempty"` // Weight per cgroup per device, can override BlkioWeight - WeightDevice []LinuxWeightDevice `protobuf:"bytes,3,rep,name=WeightDevice,proto3" json:"WeightDevice"` + WeightDevice []LinuxWeightDevice `protobuf:"bytes,3,rep,name=WeightDevice,json=weightDevice,proto3" json:"WeightDevice"` // IO read rate limit per cgroup per device, bytes per second - ThrottleReadBpsDevice []LinuxThrottleDevice `protobuf:"bytes,4,rep,name=ThrottleReadBpsDevice,proto3" json:"ThrottleReadBpsDevice"` + ThrottleReadBpsDevice []LinuxThrottleDevice `protobuf:"bytes,4,rep,name=ThrottleReadBpsDevice,json=throttleReadBpsDevice,proto3" json:"ThrottleReadBpsDevice"` // IO write rate limit per cgroup per device, bytes per second - ThrottleWriteBpsDevice []LinuxThrottleDevice `protobuf:"bytes,5,rep,name=ThrottleWriteBpsDevice,proto3" json:"ThrottleWriteBpsDevice"` + ThrottleWriteBpsDevice []LinuxThrottleDevice `protobuf:"bytes,5,rep,name=ThrottleWriteBpsDevice,json=throttleWriteBpsDevice,proto3" json:"ThrottleWriteBpsDevice"` // IO read rate limit per cgroup per device, IO per second - ThrottleReadIOPSDevice []LinuxThrottleDevice `protobuf:"bytes,6,rep,name=ThrottleReadIOPSDevice,proto3" json:"ThrottleReadIOPSDevice"` + ThrottleReadIOPSDevice []LinuxThrottleDevice `protobuf:"bytes,6,rep,name=ThrottleReadIOPSDevice,json=throttleReadIOPSDevice,proto3" json:"ThrottleReadIOPSDevice"` // IO write rate limit per cgroup per device, IO per second - ThrottleWriteIOPSDevice []LinuxThrottleDevice `protobuf:"bytes,7,rep,name=ThrottleWriteIOPSDevice,proto3" json:"ThrottleWriteIOPSDevice"` + ThrottleWriteIOPSDevice []LinuxThrottleDevice `protobuf:"bytes,7,rep,name=ThrottleWriteIOPSDevice,json=throttleWriteIOPSDevice,proto3" json:"ThrottleWriteIOPSDevice"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1090,7 +1090,7 @@ var xxx_messageInfo_LinuxBlockIO proto.InternalMessageInfo type LinuxPids struct { // Maximum number of PIDs. Default is "no limit". - Limit int64 `protobuf:"varint,1,opt,name=Limit,proto3" json:"Limit,omitempty"` + Limit int64 `protobuf:"varint,1,opt,name=Limit,json=limit,proto3" json:"Limit,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1130,15 +1130,15 @@ var xxx_messageInfo_LinuxPids proto.InternalMessageInfo type LinuxDeviceCgroup struct { // Allow or deny - Allow bool `protobuf:"varint,1,opt,name=Allow,proto3" json:"Allow,omitempty"` + Allow bool `protobuf:"varint,1,opt,name=Allow,json=allow,proto3" json:"Allow,omitempty"` // Device type, block, char, etc. - Type string `protobuf:"bytes,2,opt,name=Type,proto3" json:"Type,omitempty"` + Type string `protobuf:"bytes,2,opt,name=Type,json=type,proto3" json:"Type,omitempty"` // Major is the device's major number. - Major int64 `protobuf:"varint,3,opt,name=Major,proto3" json:"Major,omitempty"` + Major int64 `protobuf:"varint,3,opt,name=Major,json=major,proto3" json:"Major,omitempty"` // Minor is the device's minor number. - Minor int64 `protobuf:"varint,4,opt,name=Minor,proto3" json:"Minor,omitempty"` + Minor int64 `protobuf:"varint,4,opt,name=Minor,json=minor,proto3" json:"Minor,omitempty"` // Cgroup access permissions format, rwm. - Access string `protobuf:"bytes,5,opt,name=Access,proto3" json:"Access,omitempty"` + Access string `protobuf:"bytes,5,opt,name=Access,json=access,proto3" json:"Access,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1178,9 +1178,9 @@ var xxx_messageInfo_LinuxDeviceCgroup proto.InternalMessageInfo type LinuxNetwork struct { // Set class identifier for container's network packets - ClassID uint32 `protobuf:"varint,1,opt,name=ClassID,proto3" json:"ClassID,omitempty"` + ClassID uint32 `protobuf:"varint,1,opt,name=ClassID,json=classID,proto3" json:"ClassID,omitempty"` // Set priority of network traffic for container - Priorities []LinuxInterfacePriority `protobuf:"bytes,2,rep,name=Priorities,proto3" json:"Priorities"` + Priorities []LinuxInterfacePriority `protobuf:"bytes,2,rep,name=Priorities,json=priorities,proto3" json:"Priorities"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1220,9 +1220,9 @@ var xxx_messageInfo_LinuxNetwork proto.InternalMessageInfo type LinuxHugepageLimit struct { // Pagesize is the hugepage size - Pagesize string `protobuf:"bytes,1,opt,name=Pagesize,proto3" json:"Pagesize,omitempty"` + Pagesize string `protobuf:"bytes,1,opt,name=Pagesize,json=pagesize,proto3" json:"Pagesize,omitempty"` // Limit is the limit of "hugepagesize" hugetlb usage - Limit uint64 `protobuf:"varint,2,opt,name=Limit,proto3" json:"Limit,omitempty"` + Limit uint64 `protobuf:"varint,2,opt,name=Limit,json=limit,proto3" json:"Limit,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1262,9 +1262,9 @@ var xxx_messageInfo_LinuxHugepageLimit proto.InternalMessageInfo type LinuxInterfacePriority struct { // Name is the name of the network interface - Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"` + Name string `protobuf:"bytes,1,opt,name=Name,json=name,proto3" json:"Name,omitempty"` // Priority for the interface - Priority uint32 `protobuf:"varint,2,opt,name=Priority,proto3" json:"Priority,omitempty"` + Priority uint32 `protobuf:"varint,2,opt,name=Priority,json=priority,proto3" json:"Priority,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1303,10 +1303,10 @@ func (m *LinuxInterfacePriority) XXX_DiscardUnknown() { var xxx_messageInfo_LinuxInterfacePriority proto.InternalMessageInfo type LinuxSeccomp struct { - DefaultAction string `protobuf:"bytes,1,opt,name=DefaultAction,proto3" json:"DefaultAction,omitempty"` - Architectures []string `protobuf:"bytes,2,rep,name=Architectures,proto3" json:"Architectures,omitempty"` - Flags []string `protobuf:"bytes,3,rep,name=Flags,proto3" json:"Flags,omitempty"` - Syscalls []LinuxSyscall `protobuf:"bytes,4,rep,name=Syscalls,proto3" json:"Syscalls"` + DefaultAction string `protobuf:"bytes,1,opt,name=DefaultAction,json=defaultAction,proto3" json:"DefaultAction,omitempty"` + Architectures []string `protobuf:"bytes,2,rep,name=Architectures,json=architectures,proto3" json:"Architectures,omitempty"` + Flags []string `protobuf:"bytes,3,rep,name=Flags,json=flags,proto3" json:"Flags,omitempty"` + Syscalls []LinuxSyscall `protobuf:"bytes,4,rep,name=Syscalls,json=syscalls,proto3" json:"Syscalls"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1345,10 +1345,10 @@ func (m *LinuxSeccomp) XXX_DiscardUnknown() { var xxx_messageInfo_LinuxSeccomp proto.InternalMessageInfo type LinuxSeccompArg struct { - Index uint64 `protobuf:"varint,1,opt,name=Index,proto3" json:"Index,omitempty"` - Value uint64 `protobuf:"varint,2,opt,name=Value,proto3" json:"Value,omitempty"` - ValueTwo uint64 `protobuf:"varint,3,opt,name=ValueTwo,proto3" json:"ValueTwo,omitempty"` - Op string `protobuf:"bytes,4,opt,name=Op,proto3" json:"Op,omitempty"` + Index uint64 `protobuf:"varint,1,opt,name=Index,json=index,proto3" json:"Index,omitempty"` + Value uint64 `protobuf:"varint,2,opt,name=Value,json=value,proto3" json:"Value,omitempty"` + ValueTwo uint64 `protobuf:"varint,3,opt,name=ValueTwo,json=valueTwo,proto3" json:"ValueTwo,omitempty"` + Op string `protobuf:"bytes,4,opt,name=Op,json=op,proto3" json:"Op,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1387,12 +1387,12 @@ func (m *LinuxSeccompArg) XXX_DiscardUnknown() { var xxx_messageInfo_LinuxSeccompArg proto.InternalMessageInfo type LinuxSyscall struct { - Names []string `protobuf:"bytes,1,rep,name=Names,proto3" json:"Names,omitempty"` - Action string `protobuf:"bytes,2,opt,name=Action,proto3" json:"Action,omitempty"` + Names []string `protobuf:"bytes,1,rep,name=Names,json=names,proto3" json:"Names,omitempty"` + Action string `protobuf:"bytes,2,opt,name=Action,json=action,proto3" json:"Action,omitempty"` // Types that are valid to be assigned to ErrnoRet: // *LinuxSyscall_Errnoret ErrnoRet isLinuxSyscall_ErrnoRet `protobuf_oneof:"ErrnoRet"` - Args []LinuxSeccompArg `protobuf:"bytes,4,rep,name=Args,proto3" json:"Args"` + Args []LinuxSeccompArg `protobuf:"bytes,4,rep,name=Args,json=args,proto3" json:"Args"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1467,7 +1467,7 @@ func (*LinuxSyscall) XXX_OneofWrappers() []interface{} { type LinuxIntelRdt struct { // The schema for L3 cache id and capacity bitmask (CBM) // Format: "L3:=;=;..." - L3CacheSchema string `protobuf:"bytes,1,opt,name=L3CacheSchema,proto3" json:"L3CacheSchema,omitempty"` + L3CacheSchema string `protobuf:"bytes,1,opt,name=L3CacheSchema,json=l3CacheSchema,proto3" json:"L3CacheSchema,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1546,140 +1546,150 @@ func init() { } var fileDescriptor_e42fef2823778fc8 = []byte{ - // 2118 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x58, 0xcb, 0x73, 0x5b, 0x49, - 0xd5, 0xcf, 0x95, 0x64, 0x59, 0x6a, 0xc5, 0x79, 0xf4, 0x64, 0x32, 0xf7, 0xcb, 0x97, 0xd2, 0x78, - 0x2e, 0x29, 0x30, 0x10, 0xec, 0x22, 0xe1, 0x31, 0x0c, 0x8f, 0x2a, 0xd9, 0x4e, 0x62, 0xd5, 0xc4, - 0x91, 0x68, 0xd9, 0x13, 0x98, 0xc5, 0x54, 0xb5, 0xaf, 0xda, 0x52, 0x8f, 0xaf, 0x6e, 0xdf, 0xea, - 0xdb, 0xb2, 0x63, 0x56, 0xb0, 0x63, 0xcf, 0x82, 0x35, 0x1b, 0x1e, 0xff, 0x01, 0xc5, 0x8a, 0x1d, - 0x29, 0x56, 0x2c, 0xa9, 0xa2, 0x0a, 0x88, 0xf7, 0xec, 0x59, 0x52, 0xa7, 0xfb, 0xdc, 0xab, 0x96, - 0xe4, 0xc0, 0x04, 0x56, 0xea, 0xf3, 0x3b, 0x8f, 0x7e, 0x9c, 0xe7, 0x15, 0xe9, 0x8d, 0xa4, 0x19, - 0x4f, 0x8f, 0x36, 0x63, 0x35, 0xd9, 0x3a, 0xe1, 0x86, 0x7f, 0x25, 0x56, 0xa9, 0xe1, 0x32, 0x15, - 0x3a, 0x5f, 0xa2, 0x73, 0x1d, 0x6f, 0xf1, 0x91, 0x48, 0xcd, 0x56, 0xa6, 0x95, 0x51, 0xb1, 0x4a, - 0x72, 0xb7, 0xca, 0xb7, 0x54, 0x2c, 0x37, 0xed, 0x92, 0xd6, 0x46, 0x3a, 0x8b, 0xef, 0x44, 0x23, - 0x35, 0x52, 0x8e, 0x79, 0x34, 0x3d, 0xde, 0x02, 0xca, 0x12, 0x76, 0xe5, 0x24, 0xa3, 0x3f, 0x54, - 0x49, 0x6d, 0x90, 0x89, 0x98, 0x86, 0x64, 0xf5, 0x23, 0xa1, 0x73, 0xa9, 0xd2, 0x30, 0x58, 0x0f, - 0x36, 0x9a, 0xac, 0x20, 0xe9, 0x17, 0xc8, 0x6a, 0x5f, 0xab, 0x58, 0xe4, 0x79, 0x58, 0x59, 0x0f, - 0x36, 0x5a, 0x0f, 0xd6, 0x36, 0xc1, 0xfc, 0x26, 0x82, 0xac, 0xe0, 0xd2, 0x36, 0xa9, 0x31, 0xa5, - 0x4c, 0x58, 0xb5, 0x52, 0xc4, 0x49, 0x01, 0xc2, 0x2c, 0x4e, 0xef, 0x90, 0xc6, 0x9e, 0xca, 0x4d, - 0xca, 0x27, 0x22, 0xac, 0xd9, 0x3d, 0x4a, 0x9a, 0x7e, 0x91, 0xd4, 0xf7, 0xd5, 0x34, 0x35, 0x79, - 0xb8, 0xb2, 0x5e, 0xdd, 0x68, 0x3d, 0x68, 0x39, 0x6d, 0x8b, 0x6d, 0xd7, 0x5e, 0xfe, 0xf5, 0xdd, - 0x2b, 0x0c, 0x05, 0xe8, 0x7b, 0x64, 0x65, 0x4f, 0xa9, 0x93, 0x3c, 0xac, 0xdb, 0x7d, 0x50, 0xd2, - 0x42, 0xcc, 0x71, 0xe8, 0x77, 0x49, 0xab, 0x93, 0xa6, 0xca, 0x70, 0x23, 0x55, 0x9a, 0x87, 0xab, - 0xd6, 0xe4, 0xff, 0x3b, 0x41, 0xb8, 0xed, 0xa6, 0xc7, 0x7d, 0x94, 0x1a, 0x7d, 0xce, 0x7c, 0x79, - 0xd8, 0xe1, 0xa9, 0x4c, 0xa7, 0x2f, 0xc2, 0x86, 0xbf, 0x83, 0x85, 0x98, 0xe3, 0xc0, 0xa3, 0x0c, - 0x54, 0xc2, 0xb5, 0xcc, 0xc3, 0xa6, 0xff, 0x28, 0x08, 0xb2, 0x82, 0x0b, 0x82, 0xcf, 0x65, 0x3a, - 0x54, 0x67, 0x79, 0x48, 0x7c, 0x41, 0x04, 0x59, 0xc1, 0xbd, 0xf3, 0x3d, 0x72, 0x63, 0xf1, 0x54, - 0xf4, 0x06, 0xa9, 0x9e, 0x88, 0x73, 0x74, 0x08, 0x2c, 0xe9, 0x2d, 0xb2, 0x72, 0xca, 0x93, 0xa9, - 0xb0, 0xae, 0x68, 0x32, 0x47, 0x7c, 0x50, 0x79, 0x3f, 0x88, 0x7e, 0x57, 0x2d, 0xfd, 0x04, 0x2f, - 0x7d, 0x20, 0xf4, 0x44, 0xa6, 0x3c, 0xb1, 0xca, 0x0d, 0x56, 0xd2, 0xf4, 0xcb, 0xa4, 0xb5, 0xa3, - 0xd2, 0x5c, 0x25, 0x62, 0x20, 0x7f, 0x24, 0xd0, 0xa5, 0x4d, 0x77, 0xa8, 0x6d, 0xf5, 0x82, 0xf9, - 0x5c, 0x7a, 0x8f, 0xd4, 0x0e, 0x73, 0xa1, 0xe7, 0x5d, 0x0a, 0x08, 0xfa, 0xc4, 0x72, 0x29, 0x25, - 0xb5, 0x8e, 0x1e, 0xe5, 0x61, 0x6d, 0xbd, 0xba, 0xd1, 0x64, 0x76, 0x0d, 0x47, 0x7f, 0x94, 0x9e, - 0x5a, 0x6f, 0x36, 0x19, 0x2c, 0x01, 0xd9, 0x39, 0x1b, 0x5a, 0xaf, 0x35, 0x19, 0x2c, 0xe9, 0xb7, - 0xc9, 0xd5, 0x1d, 0x9e, 0xf1, 0x23, 0x99, 0x48, 0x23, 0x05, 0xf8, 0x09, 0x76, 0x79, 0xc7, 0x7b, - 0x6e, 0x9f, 0xcd, 0xe6, 0x84, 0xe9, 0x57, 0xc9, 0x2a, 0x4b, 0xe4, 0x44, 0x9a, 0x3c, 0x6c, 0x58, - 0xff, 0xde, 0xc4, 0xb0, 0xec, 0x0d, 0xba, 0x3f, 0x70, 0x1c, 0x3c, 0x64, 0x21, 0x47, 0x37, 0xc8, - 0xf5, 0x67, 0xea, 0x99, 0x38, 0xeb, 0x6b, 0x79, 0x2a, 0x13, 0x31, 0x12, 0xce, 0x79, 0x0d, 0xb6, - 0x08, 0x83, 0x64, 0x27, 0xcb, 0xb8, 0x9e, 0x28, 0xdd, 0xd7, 0xea, 0x58, 0x26, 0xc2, 0x7a, 0xaf, - 0xc9, 0x16, 0x61, 0xba, 0x4e, 0x5a, 0xbd, 0xde, 0xfe, 0x20, 0x56, 0x5a, 0x74, 0x86, 0x9f, 0x86, - 0xad, 0xf5, 0x60, 0xa3, 0xca, 0x7c, 0x88, 0x46, 0xe4, 0xea, 0x40, 0x24, 0x70, 0x9b, 0xa7, 0xfc, - 0x48, 0x24, 0xe1, 0x55, 0x6b, 0x68, 0x0e, 0x8b, 0x1e, 0x92, 0xea, 0xb6, 0x7a, 0x41, 0x6f, 0x93, - 0xfa, 0x9e, 0x90, 0xa3, 0xb1, 0xb1, 0x5e, 0x5b, 0x63, 0x48, 0x81, 0xd7, 0x9f, 0xcb, 0xa1, 0x19, - 0x5b, 0x6f, 0xad, 0x31, 0x47, 0x44, 0xa9, 0x73, 0x0e, 0x3c, 0xec, 0x61, 0x77, 0x17, 0x55, 0x60, - 0x09, 0xc8, 0x93, 0xee, 0x2e, 0x4a, 0xc3, 0x92, 0x7e, 0x9e, 0x5c, 0xeb, 0x0c, 0x87, 0x12, 0x62, - 0x8b, 0x27, 0x4f, 0xe4, 0x30, 0x0f, 0xab, 0xeb, 0xd5, 0x8d, 0x35, 0xb6, 0x80, 0x42, 0xe4, 0x80, - 0x4d, 0x3f, 0x47, 0x0b, 0x3a, 0xfa, 0x55, 0x40, 0x6e, 0x2e, 0x79, 0x05, 0x34, 0xb6, 0xd5, 0x34, - 0x1d, 0xca, 0x74, 0x14, 0x06, 0xd6, 0xdb, 0x25, 0x4d, 0xef, 0x92, 0xe6, 0xa3, 0xe3, 0x63, 0x11, - 0x1b, 0x79, 0x0a, 0x91, 0x06, 0xcc, 0x19, 0x00, 0x4f, 0xd7, 0x4d, 0xc7, 0x42, 0x4b, 0xc3, 0x8f, - 0x12, 0x61, 0x0f, 0xd4, 0x64, 0x3e, 0x04, 0xfa, 0x7d, 0x88, 0x5b, 0x63, 0xc4, 0x10, 0xa3, 0x6b, - 0x06, 0x40, 0xc9, 0xea, 0x4c, 0x8e, 0xa4, 0x48, 0x0d, 0x86, 0x59, 0x41, 0x46, 0x5d, 0xd2, 0xf2, - 0xc2, 0x00, 0xe2, 0xf3, 0xe0, 0x3c, 0x13, 0x98, 0x47, 0x76, 0x0d, 0xd8, 0x1e, 0xd7, 0x43, 0xfb, - 0x46, 0x35, 0x66, 0xd7, 0x80, 0x0d, 0xd4, 0xb1, 0x2b, 0x60, 0x35, 0x66, 0xd7, 0x91, 0x22, 0x2b, - 0xb6, 0xee, 0xc0, 0x69, 0x87, 0x22, 0x37, 0x32, 0xb5, 0x09, 0x8a, 0xb6, 0x7c, 0x08, 0xbc, 0x97, - 0xab, 0xa9, 0x8e, 0x8b, 0xe4, 0x44, 0x0a, 0xcc, 0x1a, 0xd8, 0xbe, 0xea, 0xb6, 0x87, 0x35, 0x9c, - 0x5d, 0x65, 0xae, 0x3a, 0xb9, 0x7b, 0x15, 0x64, 0xf4, 0x0d, 0x57, 0x45, 0x41, 0xab, 0xcf, 0xcd, - 0xb8, 0x38, 0x34, 0xac, 0xe1, 0xad, 0x99, 0xe0, 0x43, 0x95, 0x26, 0xe7, 0x76, 0x8f, 0x06, 0x2b, - 0xe9, 0xe8, 0x67, 0x01, 0xd6, 0x45, 0x7a, 0x9f, 0x34, 0xfa, 0x5a, 0xe4, 0x86, 0x6b, 0x63, 0x3d, - 0x52, 0x26, 0x2e, 0xb0, 0x31, 0x27, 0x4a, 0x09, 0xba, 0x49, 0x9a, 0x7d, 0x95, 0x1b, 0x27, 0x5e, - 0x79, 0x8d, 0xf8, 0x4c, 0xc4, 0x5a, 0xb7, 0x84, 0xca, 0xac, 0xcb, 0x2e, 0xb7, 0x8e, 0x12, 0xd1, - 0xc7, 0xa4, 0x06, 0xf8, 0xa5, 0xb7, 0x29, 0xca, 0x46, 0x65, 0xb9, 0x6c, 0x54, 0x67, 0x65, 0x23, - 0x24, 0xab, 0x07, 0x72, 0x22, 0xd4, 0xd4, 0xd8, 0x80, 0xac, 0xb2, 0x82, 0x8c, 0x7e, 0xb3, 0x82, - 0x75, 0x9a, 0x7e, 0x87, 0xb4, 0x0e, 0xbb, 0xbb, 0xfb, 0x3c, 0xcb, 0x64, 0x3a, 0xca, 0xf1, 0xd2, - 0xb7, 0xbc, 0x3a, 0x52, 0x32, 0xf1, 0x80, 0xbe, 0x38, 0x68, 0x3f, 0xf1, 0xb4, 0x2b, 0xff, 0x59, - 0xdb, 0x13, 0xa7, 0x5b, 0xa4, 0x3e, 0x38, 0xcf, 0x63, 0x93, 0xe0, 0x6b, 0xf8, 0xe5, 0x6b, 0xd3, - 0x71, 0x5c, 0x8b, 0x41, 0x31, 0xfa, 0x80, 0x34, 0x99, 0x70, 0xa1, 0x91, 0xdb, 0x2b, 0xcd, 0x6f, - 0x56, 0xf2, 0xd8, 0x4c, 0x0c, 0x82, 0x6f, 0x67, 0xa4, 0xd5, 0x34, 0xcb, 0xed, 0x2b, 0xae, 0xb8, - 0xe0, 0xf3, 0x20, 0xfa, 0x01, 0x21, 0xcf, 0xf8, 0x44, 0xe4, 0x19, 0x07, 0xb3, 0xf5, 0xa5, 0x3b, - 0x94, 0x4c, 0xbc, 0x83, 0x27, 0x0d, 0xa5, 0x74, 0x57, 0x9c, 0xca, 0x58, 0x14, 0xad, 0xf2, 0xa6, - 0xa7, 0xe8, 0x38, 0x45, 0x29, 0x45, 0x39, 0x7a, 0x9f, 0xac, 0x0e, 0x44, 0x1c, 0xab, 0x49, 0x86, - 0x4d, 0x92, 0x7a, 0x2a, 0xc8, 0x61, 0x85, 0x08, 0xbd, 0x4f, 0x6e, 0x42, 0x4c, 0x1f, 0xe7, 0x7d, - 0xad, 0x32, 0x3e, 0x72, 0x19, 0xd4, 0xb4, 0x97, 0x58, 0x66, 0xc0, 0x65, 0xf7, 0x79, 0x7e, 0x22, - 0x86, 0x70, 0x31, 0x68, 0x9b, 0xb6, 0x2e, 0x78, 0x10, 0xbd, 0x47, 0xd6, 0x8a, 0xb8, 0x77, 0x32, - 0x2d, 0x2b, 0x33, 0x0f, 0xd2, 0x36, 0x21, 0x36, 0x75, 0xfd, 0xb2, 0xeb, 0x21, 0x74, 0x8b, 0x34, - 0xba, 0xa9, 0x11, 0x09, 0x1b, 0x9a, 0x70, 0xcd, 0x5e, 0xe2, 0x2d, 0xdf, 0xe9, 0xc8, 0x62, 0xa5, - 0xd0, 0x9d, 0x6f, 0x91, 0x96, 0xe7, 0xd0, 0x37, 0xea, 0xce, 0xef, 0x96, 0x63, 0x00, 0x08, 0x0d, - 0xa7, 0x93, 0x49, 0xa1, 0xe8, 0x08, 0x10, 0x28, 0x46, 0x86, 0xcb, 0x05, 0x3e, 0x21, 0xd7, 0xe6, - 0x83, 0xd1, 0x76, 0x0b, 0x95, 0x9b, 0xb2, 0xf4, 0x23, 0x65, 0x83, 0xa5, 0x18, 0x18, 0xcb, 0x2e, - 0xe0, 0x43, 0xb6, 0xd0, 0x41, 0xf3, 0xaf, 0x5a, 0x96, 0x5d, 0x47, 0xef, 0xa3, 0xfd, 0x32, 0x2e, - 0x5e, 0x57, 0x36, 0x6d, 0x04, 0x56, 0x66, 0x79, 0x1c, 0xfd, 0x22, 0x20, 0x2d, 0x2f, 0x54, 0x5e, - 0x97, 0xeb, 0xd6, 0x56, 0xc5, 0xb3, 0x75, 0x8b, 0xac, 0xec, 0xf3, 0x4f, 0x95, 0x9b, 0x2e, 0xaa, - 0xcc, 0x11, 0x16, 0x95, 0xa9, 0xd2, 0x98, 0xed, 0x8e, 0x80, 0xca, 0xf7, 0x58, 0x26, 0x62, 0x5f, - 0x0d, 0x85, 0x8d, 0xfe, 0x35, 0x56, 0xd2, 0x45, 0xff, 0xab, 0x2f, 0xf5, 0xbf, 0xd5, 0xb2, 0xff, - 0x45, 0x7f, 0xab, 0xe0, 0xf5, 0x66, 0x39, 0xf5, 0xcd, 0x59, 0xd4, 0x07, 0x4b, 0x99, 0xeb, 0x38, - 0x2e, 0xc1, 0x16, 0x63, 0x1f, 0x66, 0x55, 0x31, 0x51, 0xfa, 0x1c, 0x87, 0x27, 0x3f, 0x5b, 0x1c, - 0x83, 0xa1, 0x00, 0x5d, 0x27, 0xd5, 0x9d, 0xfe, 0x21, 0x8e, 0x4f, 0xd7, 0xfc, 0xc1, 0xa6, 0x7f, - 0xc8, 0x80, 0x45, 0x3f, 0x47, 0x6a, 0x7d, 0x68, 0xc7, 0xae, 0x10, 0x5c, 0xf7, 0x44, 0x00, 0x66, - 0x96, 0x09, 0xd9, 0xb6, 0x9d, 0xa8, 0xf8, 0xa4, 0xdb, 0xb3, 0x97, 0x9f, 0xcf, 0x36, 0xe4, 0xb0, - 0x42, 0x84, 0x3e, 0x26, 0xd7, 0xf6, 0xa6, 0x23, 0x91, 0xf1, 0x91, 0x78, 0xea, 0x06, 0x24, 0x57, - 0x0e, 0x42, 0x4f, 0x69, 0x4e, 0x00, 0x2f, 0xb8, 0xa0, 0x05, 0xbb, 0x3e, 0x13, 0xe6, 0x4c, 0xe9, - 0x13, 0x9c, 0xcc, 0xfc, 0x5d, 0x91, 0xc3, 0x0a, 0x91, 0xe8, 0x2f, 0x45, 0x14, 0xe0, 0xd5, 0x6f, - 0x41, 0x71, 0x9e, 0x48, 0x37, 0xca, 0x54, 0x99, 0x23, 0x20, 0x36, 0x99, 0xc8, 0x85, 0x3e, 0x75, - 0x35, 0xa0, 0xe2, 0xc6, 0x25, 0x0f, 0xb2, 0xb1, 0x79, 0xc6, 0x33, 0x0c, 0x0a, 0xbb, 0x86, 0x48, - 0xff, 0x50, 0xe8, 0x54, 0x24, 0x18, 0x14, 0x48, 0xc1, 0x7c, 0xe0, 0x56, 0x07, 0x3b, 0x7d, 0xfb, - 0x32, 0x55, 0x36, 0x03, 0x20, 0xff, 0x41, 0x3b, 0x93, 0x29, 0x7c, 0xbb, 0xd4, 0x6d, 0x53, 0xf7, - 0x10, 0xfa, 0x25, 0x72, 0x63, 0x57, 0xe6, 0x30, 0x68, 0xf4, 0x7a, 0xfb, 0x1f, 0xca, 0x24, 0x11, - 0xda, 0x5e, 0xb4, 0xc1, 0x96, 0xf0, 0xe8, 0x8f, 0x01, 0x69, 0x14, 0x8e, 0x83, 0xe3, 0x0c, 0xc6, - 0x5c, 0xdb, 0xc0, 0x01, 0xa3, 0x48, 0xc1, 0x95, 0xbf, 0x3f, 0x55, 0x86, 0xe3, 0xb5, 0x1c, 0x01, - 0xd2, 0x7d, 0xa1, 0xa5, 0x1a, 0xe2, 0x5c, 0x81, 0x14, 0xcc, 0x98, 0x4c, 0xf0, 0xc4, 0xc8, 0x89, - 0x60, 0xd3, 0x14, 0x7e, 0xf0, 0x76, 0x8b, 0x30, 0x0c, 0x6f, 0x05, 0x84, 0x96, 0x56, 0xac, 0xa5, - 0x05, 0x14, 0x9e, 0x6e, 0x27, 0x9b, 0xe6, 0x38, 0x62, 0xdb, 0x35, 0x60, 0xfb, 0x62, 0xe2, 0x66, - 0xeb, 0x26, 0xb3, 0xeb, 0xe8, 0x0c, 0xe7, 0xb8, 0xe7, 0x76, 0xba, 0xc4, 0xac, 0x2d, 0xb3, 0x31, - 0xb8, 0x34, 0x1b, 0x2b, 0x7e, 0x36, 0xde, 0x26, 0x75, 0xa7, 0x8b, 0x15, 0x04, 0x29, 0x78, 0xf1, - 0xa7, 0x82, 0x1f, 0x23, 0xaf, 0x66, 0x79, 0x1e, 0x12, 0x1d, 0x92, 0xb7, 0xec, 0xc6, 0x07, 0x63, - 0xad, 0x8c, 0x49, 0xc4, 0x7f, 0xb1, 0x35, 0x25, 0x35, 0xc6, 0x8d, 0x28, 0x66, 0x34, 0x58, 0x47, - 0xff, 0xa8, 0x92, 0xab, 0x7e, 0x2a, 0x78, 0xe7, 0x0b, 0xfe, 0xcd, 0xf9, 0x2a, 0x8b, 0xe7, 0xa3, - 0x1d, 0x72, 0xd5, 0x7f, 0x93, 0x4b, 0x3a, 0xba, 0xcf, 0xc6, 0xb4, 0x99, 0x53, 0xa1, 0x87, 0xe4, - 0xed, 0xe2, 0x76, 0xd0, 0x8d, 0xb6, 0xb3, 0x1c, 0x6d, 0xd5, 0xac, 0xad, 0xff, 0xf3, 0x6c, 0xcd, - 0xbf, 0x02, 0x5a, 0xbb, 0x5c, 0x9b, 0x3e, 0x27, 0xb7, 0x0b, 0xc6, 0x73, 0x2d, 0x8d, 0x98, 0xd9, - 0x5d, 0xf9, 0x6c, 0x76, 0x5f, 0xa3, 0xee, 0x1b, 0x86, 0x1d, 0xbb, 0xbd, 0xfe, 0x00, 0x0d, 0xd7, - 0xdf, 0xd0, 0xf0, 0xbc, 0x3a, 0xfd, 0x21, 0x79, 0x67, 0x6e, 0x4b, 0xcf, 0xf2, 0xea, 0x67, 0xb3, - 0xfc, 0x3a, 0xfd, 0xe8, 0x3d, 0xd2, 0x2c, 0x2b, 0xe4, 0xe5, 0x75, 0x26, 0xfa, 0x49, 0xf1, 0xad, - 0xe2, 0x17, 0x72, 0x90, 0xed, 0x24, 0x89, 0x3a, 0xc3, 0x8f, 0x62, 0x47, 0xfc, 0xcf, 0xbd, 0xe9, - 0x36, 0xa9, 0x77, 0x62, 0xfb, 0xff, 0x88, 0x9b, 0xcb, 0x90, 0x8a, 0x12, 0x8c, 0x4a, 0xac, 0x90, - 0x30, 0xc9, 0xee, 0x24, 0x3c, 0xcf, 0xcb, 0x86, 0x5d, 0x90, 0x74, 0x9b, 0x90, 0xbe, 0x96, 0x4a, - 0xbb, 0xcf, 0x60, 0x37, 0x80, 0xde, 0x5d, 0x98, 0x45, 0xf4, 0x31, 0x8f, 0x05, 0x4a, 0x9d, 0x17, - 0x43, 0xdc, 0x4c, 0x2b, 0x7a, 0x4c, 0xe8, 0x72, 0x65, 0x87, 0xbe, 0xd9, 0xe7, 0x23, 0x91, 0x43, - 0xb7, 0x77, 0xfd, 0xb8, 0xa4, 0x67, 0x2f, 0xe7, 0xbe, 0x81, 0xf0, 0xe5, 0xf6, 0xc8, 0xed, 0xcb, - 0xf7, 0x84, 0x77, 0x82, 0xe1, 0xa0, 0xe8, 0xeb, 0xb0, 0xb6, 0xf6, 0x91, 0x8f, 0xf9, 0x54, 0xd2, - 0xd1, 0x2f, 0x03, 0x7c, 0x80, 0x62, 0x0c, 0xbc, 0x47, 0xd6, 0x76, 0xc5, 0x31, 0x9f, 0x26, 0xa6, - 0x13, 0x7b, 0x1f, 0x51, 0xf3, 0x20, 0x48, 0x75, 0x74, 0x3c, 0x96, 0x46, 0xc4, 0x66, 0xaa, 0x45, - 0xf1, 0x7d, 0x30, 0x0f, 0xc2, 0xe1, 0x1f, 0x27, 0x7c, 0x94, 0xe3, 0xa7, 0x82, 0x23, 0xe8, 0xd7, - 0x48, 0x03, 0x26, 0x34, 0x9e, 0x24, 0x39, 0x26, 0xdc, 0xdc, 0x5c, 0xea, 0x58, 0xc5, 0x47, 0x4a, - 0x21, 0x19, 0x49, 0x72, 0xdd, 0x3f, 0x67, 0x47, 0x8f, 0xc0, 0x7c, 0x37, 0x1d, 0x8a, 0x17, 0x58, - 0xe1, 0x1d, 0x01, 0xe8, 0x47, 0xe5, 0x7c, 0x57, 0x63, 0x8e, 0x80, 0x37, 0xb0, 0x8b, 0x83, 0x33, - 0x85, 0x65, 0xa9, 0xa4, 0xe9, 0x35, 0x52, 0xe9, 0x65, 0xf8, 0x25, 0x5d, 0xe9, 0x65, 0xd1, 0xcf, - 0xcb, 0x37, 0x71, 0x9b, 0x83, 0x49, 0x3b, 0x71, 0xe1, 0xb7, 0xb3, 0x23, 0x5c, 0x48, 0x95, 0x1d, - 0xd2, 0x86, 0x94, 0x7d, 0x9b, 0xbb, 0xa4, 0x21, 0xb4, 0x4e, 0x95, 0x16, 0x58, 0x7a, 0xf7, 0xae, - 0xb0, 0x12, 0xa1, 0x5b, 0xde, 0xff, 0x30, 0xad, 0x07, 0x6f, 0x2f, 0x4f, 0xe4, 0x1d, 0x5d, 0x7c, - 0xc2, 0x58, 0xc1, 0x6d, 0x42, 0x1a, 0x8f, 0x40, 0x99, 0x09, 0x13, 0x7d, 0x9d, 0xac, 0xcd, 0xcd, - 0xbd, 0xe0, 0x87, 0xa7, 0x0f, 0x77, 0x78, 0x3c, 0x16, 0x83, 0x78, 0x2c, 0x26, 0xbc, 0xf0, 0xd6, - 0x1c, 0xb8, 0xfd, 0xd3, 0xe0, 0xe5, 0xab, 0xf6, 0x95, 0x3f, 0xbf, 0x6a, 0x5f, 0xf9, 0xe7, 0xab, - 0x76, 0xf0, 0xe3, 0x8b, 0x76, 0xf0, 0xeb, 0x8b, 0x76, 0xf0, 0xdb, 0x8b, 0x76, 0xf0, 0xfb, 0x8b, - 0x76, 0xf0, 0xf2, 0xa2, 0x1d, 0xfc, 0xe9, 0xa2, 0x1d, 0xfc, 0xfd, 0xa2, 0x1d, 0x7c, 0xfc, 0xc9, - 0x1b, 0xfe, 0xcd, 0xa9, 0x5d, 0xfb, 0xdb, 0x3a, 0x95, 0xda, 0x78, 0xac, 0xec, 0x64, 0xb4, 0xf4, - 0x0f, 0x28, 0xdc, 0xf4, 0xa8, 0x6e, 0xe9, 0x87, 0xff, 0x0a, 0x00, 0x00, 0xff, 0xff, 0xfb, 0x3e, - 0xc9, 0x10, 0x4f, 0x15, 0x00, 0x00, + // 2282 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x58, 0xcd, 0x73, 0x23, 0x47, + 0xd9, 0xdf, 0xd1, 0x8c, 0xa4, 0x51, 0xcb, 0x1f, 0xbb, 0x9d, 0xc4, 0xd1, 0xbb, 0x6f, 0x4a, 0x71, + 0x86, 0x14, 0x18, 0x58, 0xec, 0x62, 0xc3, 0x47, 0x08, 0x1f, 0x55, 0xb2, 0xbd, 0x1b, 0xab, 0xb2, + 0x5e, 0x8b, 0x96, 0x9d, 0x85, 0x1c, 0x52, 0xd5, 0x9e, 0x69, 0x49, 0x13, 0x8f, 0xa6, 0x87, 0xee, + 0x96, 0xb5, 0xce, 0x09, 0x6e, 0xdc, 0x39, 0x70, 0xe6, 0xc2, 0xc7, 0x7f, 0x40, 0x71, 0xe2, 0xc6, + 0x16, 0x27, 0x8e, 0x54, 0x51, 0x05, 0xac, 0xef, 0xdc, 0x39, 0x52, 0x4f, 0x77, 0xcf, 0xa8, 0x65, + 0x7b, 0x21, 0x0b, 0x27, 0xcd, 0xf3, 0x7b, 0x9e, 0x7e, 0xba, 0xfb, 0xf9, 0x6e, 0xa1, 0xa3, 0x71, + 0xaa, 0x26, 0xb3, 0xd3, 0xed, 0x98, 0x4f, 0x77, 0xce, 0xa8, 0xa2, 0x5f, 0x89, 0x79, 0xae, 0x68, + 0x9a, 0x33, 0x21, 0xaf, 0xd1, 0x52, 0xc4, 0x3b, 0x74, 0xcc, 0x72, 0xb5, 0x53, 0x08, 0xae, 0x78, + 0xcc, 0x33, 0x69, 0xbe, 0xe4, 0x0e, 0x8f, 0xd3, 0x6d, 0xfd, 0x89, 0x83, 0xb1, 0x28, 0xe2, 0xbb, + 0xd1, 0x98, 0x8f, 0xb9, 0x61, 0x9e, 0xce, 0x46, 0x3b, 0x40, 0x69, 0x42, 0x7f, 0x19, 0xc9, 0xe8, + 0x0f, 0x3e, 0x0a, 0x86, 0x05, 0x8b, 0x71, 0x07, 0x35, 0x3f, 0x64, 0x42, 0xa6, 0x3c, 0xef, 0x78, + 0x9b, 0xde, 0x56, 0x8b, 0x34, 0xcf, 0x0d, 0x89, 0xbf, 0x80, 0x9a, 0x03, 0xc1, 0x63, 0x26, 0x65, + 0xa7, 0xb6, 0xe9, 0x6d, 0xb5, 0xef, 0xaf, 0x6e, 0x83, 0xfa, 0x6d, 0x0b, 0x92, 0x66, 0x61, 0x3e, + 0x70, 0x17, 0x05, 0x84, 0x73, 0xd5, 0xf1, 0xb5, 0x14, 0x32, 0x52, 0x80, 0x90, 0x40, 0x70, 0xae, + 0xf0, 0x5d, 0x14, 0x1e, 0x70, 0xa9, 0x72, 0x3a, 0x65, 0x9d, 0x40, 0xef, 0x11, 0x4e, 0x2c, 0x8d, + 0xbf, 0x88, 0x1a, 0x87, 0x7c, 0x96, 0x2b, 0xd9, 0xa9, 0x6f, 0xfa, 0x5b, 0xed, 0xfb, 0x6d, 0xb3, + 0x5a, 0x63, 0xbb, 0xc1, 0xb3, 0xbf, 0xbe, 0x79, 0x8b, 0x34, 0xa6, 0x5a, 0x00, 0xbf, 0x85, 0xea, + 0x07, 0x9c, 0x9f, 0xc9, 0x4e, 0x43, 0xef, 0x63, 0x25, 0x35, 0x44, 0xea, 0x13, 0xf8, 0xc1, 0xdf, + 0x45, 0xed, 0x5e, 0x9e, 0x73, 0x45, 0x55, 0xca, 0x73, 0xd9, 0x69, 0x6a, 0x95, 0xff, 0x6f, 0x04, + 0xe1, 0xb6, 0xdb, 0x0e, 0xf7, 0x41, 0xae, 0xc4, 0x05, 0x69, 0xd3, 0x05, 0x02, 0x3b, 0x3c, 0x4a, + 0xf3, 0xd9, 0xd3, 0x4e, 0xe8, 0xee, 0xa0, 0x21, 0x52, 0xcf, 0xe0, 0x07, 0x8c, 0x32, 0xe4, 0x19, + 0x15, 0xa9, 0xec, 0xb4, 0x5c, 0xa3, 0x58, 0x90, 0x34, 0xa5, 0xf9, 0x00, 0xc1, 0x27, 0x69, 0x9e, + 0xf0, 0xb9, 0xec, 0x20, 0x57, 0xd0, 0x82, 0xa4, 0x39, 0x37, 0x1f, 0x77, 0xbf, 0x87, 0x6e, 0x5f, + 0x3d, 0x15, 0xbe, 0x8d, 0xfc, 0x33, 0x76, 0x61, 0x1d, 0x02, 0x9f, 0xf8, 0x55, 0x54, 0x3f, 0xa7, + 0xd9, 0x8c, 0x69, 0x57, 0xb4, 0x88, 0x21, 0xde, 0xab, 0xbd, 0xeb, 0x45, 0xbf, 0xf3, 0x2b, 0x3f, + 0x81, 0xa5, 0x8f, 0x99, 0x98, 0xa6, 0x39, 0xcd, 0xf4, 0xe2, 0x90, 0x84, 0xca, 0xd2, 0xf8, 0xcb, + 0xa8, 0xbd, 0xc7, 0x73, 0xc9, 0x33, 0x36, 0x4c, 0x3f, 0x65, 0xd6, 0xa5, 0x2d, 0x73, 0xa8, 0x5d, + 0xfe, 0x94, 0xb4, 0xe3, 0x05, 0x17, 0xbf, 0x8d, 0x82, 0x13, 0xc9, 0xc4, 0xb2, 0x4b, 0x01, 0xb1, + 0x3e, 0x09, 0x66, 0x92, 0x09, 0x8c, 0x51, 0xd0, 0x13, 0x63, 0xd9, 0x09, 0x36, 0xfd, 0xad, 0x16, + 0x09, 0xa8, 0x18, 0x4b, 0x38, 0xfa, 0x83, 0xfc, 0x5c, 0x7b, 0xb3, 0x45, 0x7c, 0x96, 0x9f, 0x03, + 0xb2, 0x37, 0x4f, 0xb4, 0xd7, 0x5a, 0xc4, 0x8f, 0xe7, 0x09, 0xfe, 0x36, 0x5a, 0xd9, 0xa3, 0x05, + 0x3d, 0x4d, 0xb3, 0x54, 0xa5, 0x0c, 0xfc, 0x04, 0xbb, 0xbc, 0xee, 0x98, 0xdb, 0x65, 0x93, 0x95, + 0xd8, 0xa1, 0xf0, 0x57, 0x51, 0x93, 0x64, 0xe9, 0x34, 0x55, 0xb2, 0x13, 0x6a, 0xff, 0xde, 0xb1, + 0x61, 0x79, 0x34, 0xec, 0xff, 0xc0, 0x70, 0xec, 0x21, 0x9b, 0xc2, 0xc8, 0xe1, 0x2d, 0xb4, 0xfe, + 0x98, 0x3f, 0x66, 0xf3, 0x81, 0x48, 0xcf, 0xd3, 0x8c, 0x8d, 0x99, 0x71, 0x5e, 0x48, 0xd6, 0xf3, + 0x65, 0x18, 0x24, 0x7b, 0x45, 0x41, 0xc5, 0x94, 0x8b, 0x81, 0xe0, 0xa3, 0x34, 0x63, 0xda, 0x7b, + 0x2d, 0xb2, 0x4e, 0x97, 0x61, 0xbc, 0x89, 0xda, 0x47, 0x47, 0x87, 0xc3, 0x98, 0x0b, 0xd6, 0x4b, + 0x3e, 0xe9, 0xb4, 0x37, 0xbd, 0x2d, 0x9f, 0xb4, 0xf9, 0x02, 0xc2, 0x11, 0x5a, 0x19, 0x32, 0x1d, + 0x35, 0x8f, 0xe8, 0x29, 0xcb, 0x3a, 0x2b, 0x5a, 0xd1, 0x8a, 0x74, 0xb0, 0xe8, 0x1d, 0xe4, 0xef, + 0xf2, 0xa7, 0x78, 0x03, 0x35, 0x0e, 0x58, 0x3a, 0x9e, 0x28, 0xed, 0xb5, 0x55, 0xd2, 0x98, 0x68, + 0x0a, 0xbc, 0xfe, 0x24, 0x4d, 0xd4, 0x44, 0x7b, 0x6b, 0x95, 0xd4, 0xe7, 0x40, 0x44, 0xb9, 0x71, + 0x0e, 0x18, 0xf6, 0xa4, 0xbf, 0x6f, 0x97, 0xf8, 0xb3, 0xfe, 0x3e, 0x20, 0xef, 0xf7, 0xf7, 0xad, + 0xb4, 0x3f, 0xee, 0xef, 0xe3, 0xcf, 0xa3, 0xb5, 0x5e, 0x92, 0xa4, 0x10, 0x5b, 0x34, 0x7b, 0x3f, + 0x4d, 0x64, 0xc7, 0xdf, 0xf4, 0xb7, 0x56, 0xc9, 0x1a, 0x5d, 0x42, 0x21, 0x72, 0x40, 0xa7, 0x9b, + 0xa3, 0x33, 0x4b, 0x47, 0xbf, 0xf2, 0xd0, 0x9d, 0x6b, 0x5e, 0x81, 0x15, 0xbb, 0x7c, 0x96, 0x27, + 0x69, 0x3e, 0xee, 0x78, 0xda, 0xdb, 0xe1, 0xa9, 0xa5, 0xf1, 0x1b, 0xa8, 0xf5, 0x60, 0x34, 0x62, + 0xb1, 0x4a, 0xcf, 0x21, 0xd2, 0x80, 0xd9, 0x62, 0x25, 0x00, 0xa6, 0xeb, 0xe7, 0x13, 0x26, 0x52, + 0x45, 0x4f, 0x33, 0xa6, 0x0f, 0xd4, 0x22, 0xed, 0x74, 0x01, 0xc1, 0xfa, 0x01, 0xc4, 0xad, 0x52, + 0x2c, 0xb1, 0xd1, 0xd5, 0x2a, 0x4a, 0x00, 0x4a, 0x56, 0x6f, 0x7a, 0x9a, 0xb2, 0x5c, 0xd9, 0x30, + 0x6b, 0x52, 0x43, 0x46, 0x7d, 0xd4, 0x76, 0xc2, 0x00, 0xe2, 0xf3, 0xf8, 0xa2, 0x60, 0x36, 0x8f, + 0x02, 0x75, 0x51, 0x30, 0xc0, 0x0e, 0xa8, 0x48, 0xb4, 0x8d, 0x02, 0x12, 0x4c, 0xa8, 0x48, 0x00, + 0x1b, 0xf2, 0x91, 0x29, 0x60, 0x01, 0x09, 0x24, 0x1f, 0xa9, 0x88, 0xa3, 0xba, 0x2e, 0x42, 0x70, + 0xda, 0x84, 0x49, 0x95, 0xe6, 0x3a, 0x41, 0xad, 0x2e, 0x17, 0x02, 0xef, 0x49, 0x3e, 0x13, 0x71, + 0x99, 0x9c, 0x96, 0x02, 0xb5, 0xb0, 0xa5, 0x56, 0x5b, 0x6e, 0xdf, 0x41, 0x4d, 0x5e, 0x98, 0xea, + 0x64, 0xee, 0x55, 0x92, 0xd1, 0x37, 0x4c, 0x15, 0x85, 0x55, 0x03, 0xaa, 0x26, 0xe5, 0xa1, 0x0b, + 0xaa, 0x26, 0x60, 0x6b, 0xc2, 0x68, 0xc2, 0xf3, 0xec, 0x42, 0xef, 0x11, 0x92, 0x50, 0x58, 0x3a, + 0xfa, 0x99, 0x67, 0xeb, 0x22, 0xbe, 0x87, 0xc2, 0x81, 0x60, 0x52, 0x51, 0xa1, 0xb4, 0x47, 0xaa, + 0xc4, 0x05, 0xb6, 0xcd, 0x89, 0xb0, 0xb0, 0x12, 0x78, 0x1b, 0xb5, 0x06, 0x5c, 0x2a, 0x23, 0x5e, + 0x7b, 0x81, 0x78, 0xab, 0x28, 0x45, 0xb4, 0x76, 0x4d, 0xf0, 0x42, 0xbb, 0xec, 0x66, 0xed, 0x56, + 0x22, 0xfa, 0x08, 0x05, 0x80, 0xdf, 0x78, 0x9b, 0xb2, 0x6c, 0xd4, 0xae, 0x97, 0x0d, 0x7f, 0x51, + 0x36, 0x3a, 0xa8, 0x79, 0x9c, 0x4e, 0x19, 0x9f, 0x29, 0x1d, 0x90, 0x3e, 0x69, 0x2a, 0x43, 0x46, + 0xbf, 0xa9, 0xdb, 0x3a, 0x8d, 0xbf, 0x83, 0xda, 0x27, 0xfd, 0xfd, 0x43, 0x5a, 0x14, 0x69, 0x3e, + 0x96, 0xf6, 0xd2, 0xaf, 0x3a, 0x75, 0xa4, 0x62, 0xda, 0x03, 0xb6, 0x67, 0x0b, 0x71, 0x58, 0xfd, + 0xbe, 0xb3, 0xba, 0xf6, 0x9f, 0x57, 0x8f, 0x9d, 0xd5, 0x3b, 0xa8, 0x31, 0xbc, 0x90, 0xb1, 0xca, + 0xac, 0x35, 0xdc, 0xf2, 0xb5, 0x6d, 0x38, 0xa6, 0xc5, 0x34, 0xa4, 0x26, 0xf0, 0x7d, 0xd4, 0x22, + 0xcc, 0x84, 0x86, 0xd4, 0x57, 0x5a, 0xde, 0xac, 0xe2, 0x91, 0x96, 0x28, 0x3f, 0x21, 0xf8, 0xf6, + 0xc6, 0x82, 0xcf, 0x0a, 0xa9, 0xad, 0x58, 0x37, 0xc1, 0x17, 0x2f, 0x20, 0xfc, 0x1e, 0x42, 0x8f, + 0xe9, 0x94, 0xc9, 0x82, 0x82, 0xda, 0xc6, 0xb5, 0x3b, 0x54, 0x4c, 0x7b, 0x07, 0x94, 0x57, 0xd2, + 0x50, 0x4a, 0xf7, 0xd9, 0x79, 0x1a, 0xb3, 0xb2, 0x55, 0xde, 0x71, 0x16, 0x1a, 0x4e, 0x59, 0x4a, + 0x13, 0x23, 0x87, 0xef, 0xa1, 0xe6, 0x90, 0xc5, 0x31, 0x9f, 0x16, 0xb6, 0x49, 0x62, 0x67, 0x89, + 0xe5, 0x90, 0xa6, 0x34, 0x1f, 0xf8, 0x1e, 0xba, 0x03, 0x31, 0x3d, 0x92, 0x03, 0xc1, 0x0b, 0x3a, + 0x36, 0x19, 0xd4, 0xd2, 0x97, 0xb8, 0x23, 0xae, 0x32, 0xe0, 0xb2, 0x87, 0x54, 0x9e, 0xb1, 0x04, + 0x2e, 0x06, 0x6d, 0x53, 0xd7, 0x85, 0xe9, 0x02, 0xc2, 0x6f, 0xa3, 0xd5, 0x32, 0x0f, 0x8c, 0x4c, + 0x5b, 0xcb, 0xac, 0x0a, 0x17, 0xc4, 0x5d, 0x84, 0x74, 0xea, 0xba, 0x65, 0x17, 0x4d, 0x2b, 0x04, + 0xef, 0xa0, 0xb0, 0x9f, 0x2b, 0x96, 0x91, 0x44, 0x75, 0x56, 0xf5, 0x25, 0x5e, 0x71, 0x9d, 0x6e, + 0x59, 0x24, 0x4c, 0xed, 0xd7, 0xdd, 0x6f, 0xa1, 0xb6, 0xe3, 0xd0, 0x97, 0xea, 0xce, 0x6f, 0x56, + 0x63, 0x00, 0x08, 0x25, 0xb3, 0xe9, 0xb4, 0x5c, 0x68, 0x08, 0x10, 0xb0, 0xb3, 0xc3, 0x0b, 0x04, + 0x3e, 0x46, 0x6b, 0xcb, 0xc1, 0xa8, 0xbb, 0x05, 0x97, 0xaa, 0x2a, 0xfd, 0x8d, 0x89, 0xa6, 0x74, + 0xb0, 0x94, 0x03, 0x63, 0xd5, 0x05, 0xda, 0xf1, 0x02, 0xd2, 0x85, 0x0e, 0x9a, 0xbf, 0xaf, 0x59, + 0x81, 0x4c, 0x3f, 0x65, 0xd1, 0xbb, 0x56, 0x7f, 0x15, 0x28, 0x2f, 0x2a, 0x9b, 0x3a, 0x02, 0x6b, + 0x8b, 0x3c, 0x8e, 0x7e, 0xe1, 0xa1, 0xb6, 0x13, 0x2a, 0x2f, 0xca, 0x75, 0xad, 0xab, 0xe6, 0xe8, + 0x7a, 0x15, 0xd5, 0x0f, 0xe9, 0x27, 0xdc, 0x4c, 0x17, 0x3e, 0xa9, 0x4f, 0x81, 0xd0, 0x68, 0x9a, + 0x73, 0x61, 0xb3, 0xbd, 0x3e, 0x05, 0x02, 0x2a, 0xdf, 0xc3, 0x34, 0x63, 0x87, 0x3c, 0x61, 0x3a, + 0xfa, 0x57, 0x49, 0x38, 0xb2, 0x74, 0xd9, 0xff, 0x1a, 0xd7, 0xfa, 0x5f, 0xb3, 0xea, 0x7f, 0xd1, + 0xdf, 0x6a, 0xf6, 0x7a, 0x55, 0x7a, 0xe1, 0x6f, 0x2e, 0xa2, 0xde, 0xbb, 0x96, 0xb9, 0x86, 0x63, + 0x72, 0xee, 0x6a, 0xec, 0xc3, 0xac, 0xca, 0xa6, 0x5c, 0x5c, 0xd8, 0xe1, 0xc9, 0xcd, 0x16, 0xc3, + 0x20, 0x8d, 0xa9, 0xfe, 0xc5, 0x9b, 0xc8, 0xdf, 0x1b, 0x9c, 0xd8, 0xf1, 0x69, 0xcd, 0x1d, 0x6c, + 0x06, 0x27, 0xc4, 0x8f, 0x07, 0x27, 0xf8, 0x73, 0x28, 0x18, 0x40, 0x3b, 0x36, 0x85, 0x60, 0xdd, + 0x11, 0x01, 0x98, 0x04, 0x05, 0x74, 0xe5, 0x7b, 0xa8, 0xb9, 0x9b, 0xf1, 0xf8, 0xac, 0x7f, 0xa4, + 0x2f, 0xbf, 0x9c, 0x6d, 0x96, 0x43, 0x9a, 0xa7, 0xe6, 0x03, 0x3f, 0x44, 0x6b, 0x07, 0xb3, 0x31, + 0x2b, 0xe8, 0x98, 0x3d, 0x32, 0x03, 0x92, 0x29, 0x07, 0x1d, 0x67, 0xd1, 0x92, 0x80, 0xbd, 0xe0, + 0xda, 0x64, 0x69, 0x15, 0xec, 0xfa, 0x98, 0xa9, 0x39, 0x17, 0x67, 0x76, 0x32, 0x73, 0x77, 0xb5, + 0x1c, 0xd2, 0xcc, 0xcd, 0x47, 0xf4, 0x97, 0x32, 0x0a, 0x8c, 0x09, 0xc0, 0x8f, 0x5a, 0x8f, 0x0e, + 0x03, 0x1f, 0xe6, 0x66, 0x68, 0xc5, 0x9b, 0xa8, 0x4d, 0x98, 0x64, 0xe2, 0xdc, 0xd4, 0x80, 0x9a, + 0x19, 0x97, 0xc4, 0x02, 0xd2, 0xb1, 0x39, 0xa7, 0x85, 0x0d, 0x8a, 0x40, 0xce, 0x69, 0x01, 0x91, + 0xfe, 0x01, 0x13, 0x39, 0xcb, 0x6c, 0x50, 0x34, 0xce, 0x34, 0x05, 0xf3, 0x81, 0xc1, 0x8f, 0xf7, + 0x06, 0xda, 0x32, 0x3e, 0x69, 0x9d, 0x95, 0x00, 0xe4, 0x3f, 0x68, 0x2a, 0xd2, 0x1c, 0xde, 0x2e, + 0x0d, 0xdd, 0xd4, 0x91, 0xac, 0x10, 0xfc, 0x25, 0x74, 0x7b, 0x3f, 0x95, 0x30, 0x68, 0x1c, 0x1d, + 0x1d, 0x7e, 0x90, 0x66, 0x19, 0x13, 0xfa, 0xa2, 0x21, 0xb9, 0x9d, 0x5c, 0xc1, 0xa3, 0x3f, 0x7a, + 0x28, 0x2c, 0x1d, 0x07, 0xc7, 0x19, 0x4e, 0xa8, 0xd0, 0x81, 0x03, 0x4a, 0x1b, 0x52, 0x53, 0x70, + 0xe5, 0xef, 0xcf, 0xb8, 0xa2, 0xf6, 0x5a, 0xf5, 0x1f, 0x01, 0x01, 0xd2, 0x03, 0x26, 0x52, 0x9e, + 0xd8, 0xb9, 0xa2, 0x51, 0x68, 0x0a, 0x66, 0x4c, 0xc2, 0x68, 0x06, 0xdd, 0x8c, 0xcc, 0x72, 0xf8, + 0xb1, 0xb7, 0x5b, 0x17, 0xcb, 0x30, 0x0c, 0x6f, 0xa5, 0xa4, 0xd5, 0x54, 0xd7, 0x9a, 0xd6, 0xc4, + 0x12, 0x0a, 0xa6, 0xdb, 0x2b, 0x66, 0xd2, 0x8e, 0xd8, 0x41, 0x5c, 0xcc, 0x24, 0x60, 0x87, 0x6c, + 0x6a, 0x66, 0xeb, 0x16, 0x09, 0xa6, 0x6c, 0x2a, 0xa3, 0xb9, 0x9d, 0xe3, 0x9e, 0xe8, 0xe9, 0xd2, + 0x66, 0x6d, 0x95, 0x8d, 0xde, 0x8d, 0xd9, 0x58, 0x73, 0xb3, 0x71, 0x03, 0x35, 0xcc, 0x5a, 0x5b, + 0x41, 0x1a, 0x73, 0x33, 0xa7, 0x76, 0x11, 0x7a, 0xc4, 0xe8, 0xc8, 0xf2, 0x02, 0xcd, 0x43, 0x59, + 0x85, 0x44, 0x27, 0xe8, 0x15, 0xbd, 0xf1, 0xf1, 0x44, 0x70, 0xa5, 0x32, 0xf6, 0x5f, 0x6c, 0x8d, + 0x51, 0x40, 0xa8, 0x62, 0xe5, 0x8c, 0x26, 0xa8, 0x62, 0xd1, 0x3f, 0x7c, 0xb4, 0xe2, 0xa6, 0x82, + 0x73, 0x3e, 0xef, 0xdf, 0x9c, 0xaf, 0x76, 0xf5, 0x7c, 0xb8, 0x87, 0x56, 0x5c, 0x9b, 0xdc, 0xd0, + 0xd1, 0x5d, 0xb6, 0x4d, 0x9b, 0x95, 0xb9, 0x6b, 0xc6, 0x13, 0xf4, 0x5a, 0x79, 0x3b, 0x68, 0x51, + 0xbb, 0x85, 0xb4, 0xba, 0x02, 0xad, 0xeb, 0xff, 0x1c, 0x5d, 0xcb, 0x56, 0xb0, 0xda, 0x5e, 0x53, + 0x37, 0xad, 0xc6, 0x4f, 0xd0, 0x46, 0x29, 0xfe, 0x44, 0xa4, 0x8a, 0x2d, 0xf4, 0xd6, 0x3f, 0x9b, + 0xde, 0x0d, 0x75, 0xe3, 0x72, 0x57, 0x31, 0xec, 0xd8, 0x3f, 0x1a, 0x0c, 0xad, 0xe2, 0xc6, 0x4b, + 0x2a, 0x5e, 0x5e, 0x8e, 0x7f, 0x88, 0x5e, 0x5f, 0x3a, 0xb1, 0xa3, 0xb9, 0xf9, 0xd9, 0x34, 0xbf, + 0xae, 0x6e, 0x5e, 0x1f, 0xbd, 0x85, 0x5a, 0x55, 0x85, 0xbc, 0xb9, 0xce, 0x44, 0x3f, 0x29, 0xdf, + 0x2a, 0x6e, 0x21, 0x07, 0xd9, 0x5e, 0x96, 0xf1, 0xb9, 0x7d, 0x14, 0xd7, 0x29, 0x10, 0xff, 0x73, + 0x6f, 0xda, 0x40, 0x8d, 0x5e, 0xac, 0xff, 0x1f, 0x31, 0x73, 0x59, 0x83, 0x6a, 0x2a, 0xca, 0x6c, + 0x54, 0xda, 0x52, 0x09, 0x93, 0xec, 0x5e, 0x46, 0xa5, 0xac, 0x1a, 0x76, 0x33, 0x36, 0x24, 0xde, + 0x45, 0x68, 0x20, 0x52, 0x2e, 0xcc, 0x33, 0xd8, 0x0c, 0xa0, 0x6f, 0x5c, 0x99, 0x45, 0xc4, 0x88, + 0xc6, 0xcc, 0x4a, 0x5d, 0x94, 0x43, 0x5c, 0x51, 0xad, 0x8a, 0x1e, 0x22, 0x7c, 0xbd, 0xb2, 0x43, + 0xdf, 0x1c, 0xd0, 0x31, 0x83, 0x0e, 0x6f, 0xfb, 0x71, 0x58, 0x58, 0x7a, 0x61, 0x39, 0xf3, 0x06, + 0xb2, 0x96, 0x3b, 0x40, 0x1b, 0x37, 0xef, 0x09, 0x76, 0x82, 0xe1, 0xa0, 0xec, 0xeb, 0xfa, 0x7f, + 0x1b, 0xd0, 0x6f, 0xf9, 0x36, 0x9f, 0x42, 0x7b, 0xa6, 0x8b, 0xe8, 0x97, 0x9e, 0x35, 0x80, 0x9d, + 0x07, 0x61, 0x6c, 0xdb, 0x67, 0x23, 0x3a, 0xcb, 0x54, 0x2f, 0x76, 0x1e, 0x51, 0xab, 0x89, 0x0b, + 0x82, 0x54, 0x4f, 0xc4, 0x93, 0x54, 0xb1, 0x58, 0xcd, 0x04, 0x2b, 0xdf, 0x07, 0xab, 0xd4, 0x05, + 0xe1, 0xf0, 0x0f, 0x33, 0x3a, 0x96, 0xf6, 0xa9, 0x50, 0x1f, 0x01, 0x81, 0xbf, 0x86, 0x42, 0x98, + 0xd0, 0x68, 0x96, 0x49, 0x9b, 0x70, 0x4b, 0x73, 0xa9, 0x61, 0x95, 0x8f, 0x14, 0x69, 0x25, 0xa3, + 0x14, 0xad, 0xbb, 0xe7, 0xec, 0x89, 0x31, 0xa8, 0xef, 0xe7, 0x09, 0x7b, 0x6a, 0x2b, 0x7c, 0x3d, + 0x05, 0x02, 0xd0, 0x0f, 0xab, 0xf9, 0x2e, 0xb0, 0xf3, 0x1d, 0xd8, 0x40, 0xa3, 0xc7, 0x73, 0x6e, + 0xcb, 0x52, 0x78, 0x6e, 0x69, 0xbc, 0x86, 0x6a, 0x47, 0x85, 0x7d, 0x49, 0xd7, 0x78, 0x11, 0xfd, + 0xbc, 0xb2, 0x89, 0xd9, 0x1c, 0x54, 0xea, 0x89, 0xcb, 0xbe, 0x9d, 0xeb, 0x7a, 0x2c, 0x37, 0x21, + 0x55, 0x75, 0x48, 0x1d, 0x52, 0xda, 0x36, 0x6f, 0xa0, 0x90, 0x09, 0x91, 0x73, 0xc1, 0x6c, 0xe9, + 0x3d, 0xb8, 0x45, 0x2a, 0x04, 0xef, 0x38, 0xff, 0xc3, 0xb4, 0xef, 0xbf, 0x76, 0x7d, 0x22, 0xef, + 0x89, 0xf2, 0x09, 0xa3, 0x5f, 0x5b, 0xbb, 0x08, 0x85, 0x0f, 0x60, 0x31, 0x61, 0x2a, 0xfa, 0x3a, + 0x5a, 0x5d, 0x9a, 0x7b, 0xc1, 0x0f, 0x8f, 0xde, 0xd9, 0xa3, 0xf1, 0x84, 0x0d, 0xe3, 0x09, 0x9b, + 0xd2, 0xd2, 0x5b, 0x99, 0x0b, 0xee, 0xfe, 0xd4, 0x7b, 0xf6, 0xbc, 0x7b, 0xeb, 0xcf, 0xcf, 0xbb, + 0xb7, 0xfe, 0xf9, 0xbc, 0xeb, 0xfd, 0xf8, 0xb2, 0xeb, 0xfd, 0xfa, 0xb2, 0xeb, 0xfd, 0xf6, 0xb2, + 0xeb, 0xfd, 0xfe, 0xb2, 0xeb, 0x3d, 0xbb, 0xec, 0x7a, 0x7f, 0xba, 0xec, 0x7a, 0x7f, 0xbf, 0xec, + 0x7a, 0x1f, 0x7d, 0xfc, 0x92, 0x7f, 0x73, 0x0a, 0xd3, 0xfe, 0x76, 0xce, 0x53, 0xa1, 0x1c, 0x56, + 0x71, 0x36, 0xbe, 0xf6, 0x0f, 0x28, 0xdc, 0xf4, 0xb4, 0xa1, 0xe9, 0x77, 0xfe, 0x15, 0x00, 0x00, + 0xff, 0xff, 0x63, 0x45, 0x7b, 0x17, 0x4f, 0x15, 0x00, 0x00, } func (this *Spec) Equal(that interface{}) bool { diff --git a/src/runtime/virtcontainers/pkg/agent/protocols/grpc/utils.go b/src/runtime/virtcontainers/pkg/agent/protocols/grpc/utils.go index ea59a3cef12c..bcb520145016 100644 --- a/src/runtime/virtcontainers/pkg/agent/protocols/grpc/utils.go +++ b/src/runtime/virtcontainers/pkg/agent/protocols/grpc/utils.go @@ -239,15 +239,6 @@ func OCItoGRPC(ociSpec *specs.Spec) (*Spec, error) { return s, err } -// GRPCtoOCI converts a gRPC specification back into an OCI representation -func GRPCtoOCI(grpcSpec *Spec) (*specs.Spec, error) { - s := &specs.Spec{} - - err := copyStruct(s, grpcSpec) - - return s, err -} - // ProcessOCItoGRPC converts an OCI process specification into its gRPC // representation func ProcessOCItoGRPC(ociProcess *specs.Process) (*Process, error) { diff --git a/src/runtime/virtcontainers/pkg/agent/protocols/grpc/utils_test.go b/src/runtime/virtcontainers/pkg/agent/protocols/grpc/utils_test.go index 3fe3e51cdbc8..066b58c44491 100644 --- a/src/runtime/virtcontainers/pkg/agent/protocols/grpc/utils_test.go +++ b/src/runtime/virtcontainers/pkg/agent/protocols/grpc/utils_test.go @@ -93,26 +93,6 @@ func TestOCItoGRPC(t *testing.T) { assertIsEqual(t, &ociSpec, spec) } -func TestGRPCtoOCI(t *testing.T) { - assert := assert.New(t) - - var ociSpec specs.Spec - - configJSONBytes, err := ioutil.ReadFile(ociConfigFile) - assert.NoError(err, "Could not open OCI config file") - - err = json.Unmarshal(configJSONBytes, &ociSpec) - assert.NoError(err, "Could not unmarshall OCI config file") - - grpcSpec, err := OCItoGRPC(&ociSpec) - assert.NoError(err, "Could not convert OCI config file") - - newOciSpec, err := GRPCtoOCI(grpcSpec) - assert.NoError(err, "Could not convert gRPC structure") - - assertIsEqual(t, newOciSpec, grpcSpec) -} - func TestProcessOCItoGRPC(t *testing.T) { assert := assert.New(t) var ociSpec specs.Spec diff --git a/src/runtime/virtcontainers/pkg/agent/protocols/types.pb.go b/src/runtime/virtcontainers/pkg/agent/protocols/types.pb.go index 263afa8f162a..74a86f03f49d 100644 --- a/src/runtime/virtcontainers/pkg/agent/protocols/types.pb.go +++ b/src/runtime/virtcontainers/pkg/agent/protocols/types.pb.go @@ -93,7 +93,7 @@ var xxx_messageInfo_IPAddress proto.InternalMessageInfo type Interface struct { Device string `protobuf:"bytes,1,opt,name=device,proto3" json:"device,omitempty"` Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - IPAddresses []*IPAddress `protobuf:"bytes,3,rep,name=IPAddresses,proto3" json:"IPAddresses,omitempty"` + IPAddresses []*IPAddress `protobuf:"bytes,3,rep,name=IPAddresses,json=iPAddresses,proto3" json:"IPAddresses,omitempty"` Mtu uint64 `protobuf:"varint,4,opt,name=mtu,proto3" json:"mtu,omitempty"` HwAddr string `protobuf:"bytes,5,opt,name=hwAddr,proto3" json:"hwAddr,omitempty"` // PCI path for the device (see the pci::Path (Rust) or types.PciPath (Go) type for format details) @@ -240,37 +240,37 @@ func init() { } var fileDescriptor_b0c68e5b9fabcd81 = []byte{ - // 472 bytes of a gzipped FileDescriptorProto + // 474 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x93, 0x31, 0x8f, 0xd3, 0x30, - 0x18, 0x86, 0xeb, 0xa6, 0xc9, 0x35, 0xae, 0x0e, 0x2a, 0x0b, 0x9d, 0x2c, 0x90, 0xa2, 0xa8, 0x0b, - 0x11, 0x12, 0x8d, 0x54, 0x10, 0xfb, 0x31, 0x9c, 0xd4, 0x05, 0x15, 0x6f, 0xb0, 0x20, 0xd7, 0x75, - 0xd3, 0xa8, 0x49, 0x1c, 0xd9, 0x4e, 0xab, 0x8a, 0x85, 0x3f, 0xc2, 0xff, 0xb9, 0x91, 0x91, 0xf1, - 0xae, 0xbf, 0x04, 0xd9, 0x4e, 0xab, 0x50, 0x58, 0x6e, 0xca, 0xfb, 0x7c, 0xb6, 0xf3, 0xbd, 0xdf, - 0x1b, 0x07, 0x7e, 0xce, 0x72, 0xbd, 0x69, 0x96, 0x53, 0x26, 0xca, 0x74, 0x4b, 0x35, 0x7d, 0xcb, - 0x44, 0xa5, 0x69, 0x5e, 0x71, 0xa9, 0xfe, 0x61, 0x25, 0x59, 0x4a, 0x33, 0x5e, 0xe9, 0xb4, 0x96, - 0x42, 0x0b, 0x26, 0x0a, 0xe5, 0x94, 0x4a, 0xf5, 0xa1, 0xe6, 0x6a, 0x6a, 0x01, 0xf9, 0x16, 0x26, - 0x4b, 0x18, 0xce, 0x17, 0xb7, 0xab, 0x95, 0xe4, 0x4a, 0xa1, 0xd7, 0x30, 0x58, 0xd3, 0x32, 0x2f, - 0x0e, 0x18, 0xc4, 0x20, 0x79, 0x36, 0x7b, 0x3e, 0x75, 0x27, 0xe6, 0x8b, 0x3b, 0x5b, 0x26, 0xed, - 0x32, 0xc2, 0xf0, 0x8a, 0xba, 0x33, 0xb8, 0x1f, 0x83, 0x24, 0x24, 0x27, 0x44, 0x08, 0x0e, 0x4a, - 0xaa, 0xb6, 0xd8, 0xb3, 0x65, 0xab, 0x27, 0x0f, 0x00, 0x86, 0xf3, 0x4a, 0x73, 0xb9, 0xa6, 0x8c, - 0xa3, 0x1b, 0x18, 0xac, 0xf8, 0x2e, 0x67, 0xdc, 0x36, 0x09, 0x49, 0x4b, 0xe6, 0x64, 0x45, 0x4b, - 0xde, 0xbe, 0xd0, 0x6a, 0x34, 0x83, 0xa3, 0xb3, 0x3b, 0xae, 0xb0, 0x17, 0x7b, 0xc9, 0x68, 0x36, - 0x3e, 0xbb, 0x6a, 0x57, 0x48, 0x77, 0x13, 0x1a, 0x43, 0xaf, 0xd4, 0x0d, 0x1e, 0xc4, 0x20, 0x19, - 0x10, 0x23, 0x4d, 0xc7, 0xcd, 0xde, 0x6c, 0xc0, 0xbe, 0xeb, 0xe8, 0xc8, 0x4c, 0x51, 0xb3, 0x7c, - 0x41, 0xf5, 0x06, 0x07, 0x6e, 0x8a, 0x16, 0x8d, 0x17, 0xd3, 0x03, 0x5f, 0x39, 0x2f, 0x46, 0xa3, - 0x57, 0x30, 0x94, 0x74, 0xff, 0x6d, 0x5d, 0xd0, 0x4c, 0xe1, 0x61, 0x0c, 0x92, 0x6b, 0x32, 0x94, - 0x74, 0x7f, 0x67, 0x78, 0xf2, 0x1d, 0xfa, 0x44, 0x34, 0xda, 0x4e, 0xb1, 0xe2, 0x4a, 0xb7, 0xb3, - 0x59, 0x6d, 0xfa, 0x64, 0x54, 0xf3, 0x3d, 0x3d, 0x9c, 0xd2, 0x6a, 0xb1, 0x93, 0x85, 0xf7, 0x57, - 0x16, 0x37, 0x30, 0x50, 0xa2, 0x91, 0x8c, 0xdb, 0x31, 0x42, 0xd2, 0x12, 0x7a, 0x01, 0x7d, 0xc5, - 0x44, 0xcd, 0xed, 0x20, 0xd7, 0xc4, 0xc1, 0xe4, 0x27, 0x80, 0xa3, 0x5b, 0xb2, 0xf8, 0xc4, 0xf3, - 0x6c, 0xb3, 0x14, 0xd2, 0xa4, 0xa6, 0xc5, 0x39, 0x12, 0x6b, 0xe5, 0xbf, 0xa9, 0x75, 0x36, 0x75, - 0x9c, 0xf4, 0x2f, 0x9d, 0x14, 0x85, 0xf9, 0xb8, 0x27, 0x87, 0x8e, 0xac, 0x13, 0x4d, 0xb5, 0x33, - 0xe8, 0x13, 0x07, 0xa6, 0xea, 0xf2, 0xf1, 0x5d, 0xd5, 0xc2, 0x9b, 0x97, 0x70, 0x78, 0xba, 0x41, - 0x28, 0x80, 0xfd, 0xdd, 0xfb, 0x71, 0xcf, 0x3e, 0x3f, 0x8c, 0xc1, 0x47, 0x75, 0xff, 0x18, 0xf5, - 0x7e, 0x3f, 0x46, 0xbd, 0x1f, 0xc7, 0x08, 0xdc, 0x1f, 0x23, 0xf0, 0xeb, 0x18, 0x81, 0x87, 0x63, - 0x04, 0xbe, 0x7e, 0x79, 0xe2, 0x9d, 0x97, 0x4d, 0xa5, 0xf3, 0x92, 0xa7, 0xbb, 0x5c, 0xea, 0xce, - 0x52, 0xbd, 0xcd, 0x2e, 0x7f, 0x87, 0x65, 0x60, 0xe5, 0xbb, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, - 0xed, 0x3e, 0x9a, 0x58, 0x57, 0x03, 0x00, 0x00, + 0x18, 0x86, 0xcf, 0x4d, 0x93, 0x6b, 0x5c, 0x1d, 0x54, 0x16, 0x3a, 0x59, 0x20, 0x45, 0x51, 0x17, + 0x22, 0x24, 0x1a, 0xa9, 0x20, 0xf6, 0x63, 0x38, 0xa9, 0x0b, 0x2a, 0xde, 0x60, 0x41, 0xae, 0xeb, + 0xa6, 0x56, 0x93, 0x38, 0xb2, 0x9d, 0x56, 0x15, 0x0b, 0x7f, 0x84, 0xff, 0x73, 0x23, 0x23, 0xe3, + 0x5d, 0x7f, 0x09, 0xb2, 0x9d, 0x96, 0x72, 0xb0, 0x30, 0xe5, 0x7d, 0x3e, 0xdb, 0xf9, 0xde, 0xef, + 0x8d, 0x03, 0x3f, 0x16, 0xc2, 0xac, 0xdb, 0xc5, 0x84, 0xc9, 0x2a, 0xdf, 0x50, 0x43, 0x5f, 0x33, + 0x59, 0x1b, 0x2a, 0x6a, 0xae, 0xf4, 0x5f, 0xac, 0x15, 0xcb, 0x69, 0xc1, 0x6b, 0x93, 0x37, 0x4a, + 0x1a, 0xc9, 0x64, 0xa9, 0xbd, 0xd2, 0xb9, 0xd9, 0x37, 0x5c, 0x4f, 0x1c, 0xa0, 0xd0, 0xc1, 0x78, + 0x01, 0xe3, 0xd9, 0xfc, 0x66, 0xb9, 0x54, 0x5c, 0x6b, 0xf4, 0x12, 0x46, 0x2b, 0x5a, 0x89, 0x72, + 0x8f, 0x41, 0x0a, 0xb2, 0x27, 0xd3, 0xa7, 0x13, 0x7f, 0x62, 0x36, 0xbf, 0x75, 0x65, 0xd2, 0x2d, + 0x23, 0x0c, 0x2f, 0xa9, 0x3f, 0x83, 0x7b, 0x29, 0xc8, 0x62, 0x72, 0x44, 0x84, 0x60, 0xbf, 0xa2, + 0x7a, 0x83, 0x03, 0x57, 0x76, 0x7a, 0x7c, 0x0f, 0x60, 0x3c, 0xab, 0x0d, 0x57, 0x2b, 0xca, 0x38, + 0xba, 0x86, 0xd1, 0x92, 0x6f, 0x05, 0xe3, 0xae, 0x49, 0x4c, 0x3a, 0xb2, 0x27, 0x6b, 0x5a, 0xf1, + 0xee, 0x85, 0x4e, 0xa3, 0x29, 0x1c, 0x9e, 0xdc, 0x71, 0x8d, 0x83, 0x34, 0xc8, 0x86, 0xd3, 0xd1, + 0xc9, 0x55, 0xb7, 0x42, 0x86, 0xe2, 0xf7, 0x26, 0x34, 0x82, 0x41, 0x65, 0x5a, 0xdc, 0x4f, 0x41, + 0xd6, 0x27, 0x56, 0xda, 0x8e, 0xeb, 0x9d, 0xdd, 0x80, 0x43, 0xdf, 0xd1, 0x93, 0x9d, 0xa2, 0x61, + 0x62, 0x4e, 0xcd, 0x1a, 0x47, 0x7e, 0x8a, 0x0e, 0xad, 0x17, 0xdb, 0x03, 0x5f, 0x7a, 0x2f, 0x56, + 0xa3, 0x17, 0x30, 0x56, 0x74, 0xf7, 0x65, 0x55, 0xd2, 0x42, 0xe3, 0x41, 0x0a, 0xb2, 0x2b, 0x32, + 0x50, 0x74, 0x77, 0x6b, 0x79, 0xfc, 0x15, 0x86, 0x44, 0xb6, 0xc6, 0x4d, 0xb1, 0xe4, 0xda, 0x74, + 0xb3, 0x39, 0x6d, 0xfb, 0x14, 0xd4, 0xf0, 0x1d, 0xdd, 0x1f, 0xd3, 0xea, 0xf0, 0x2c, 0x8b, 0xe0, + 0x8f, 0x2c, 0xae, 0x61, 0xa4, 0x65, 0xab, 0x18, 0x77, 0x63, 0xc4, 0xa4, 0x23, 0xf4, 0x0c, 0x86, + 0x9a, 0xc9, 0x86, 0xbb, 0x41, 0xae, 0x88, 0x87, 0xf1, 0x77, 0x00, 0x87, 0x37, 0x64, 0xfe, 0x81, + 0x8b, 0x62, 0xbd, 0x90, 0xca, 0xa6, 0x66, 0xe4, 0x29, 0x1d, 0x67, 0xe5, 0x9f, 0xa9, 0x9d, 0x6d, + 0x3a, 0x73, 0xd2, 0x7b, 0xec, 0xa4, 0x2c, 0xed, 0xc7, 0x3d, 0x3a, 0xf4, 0xe4, 0x9c, 0x18, 0x6a, + 0xbc, 0xc1, 0x90, 0x78, 0xb0, 0x55, 0x9f, 0x4f, 0xe8, 0xab, 0x0e, 0x5e, 0x3d, 0x87, 0x83, 0xe3, + 0x0d, 0x42, 0x11, 0xec, 0x6d, 0xdf, 0x8e, 0x2e, 0xdc, 0xf3, 0xdd, 0x08, 0xbc, 0xd7, 0x77, 0x0f, + 0xc9, 0xc5, 0xcf, 0x87, 0xe4, 0xe2, 0xdb, 0x21, 0x01, 0x77, 0x87, 0x04, 0xfc, 0x38, 0x24, 0xe0, + 0xfe, 0x90, 0x80, 0xcf, 0x9f, 0xfe, 0xf3, 0xce, 0xab, 0xb6, 0x36, 0xa2, 0xe2, 0xf9, 0x56, 0x28, + 0x73, 0xb6, 0xd4, 0x6c, 0x8a, 0xc7, 0xbf, 0xc3, 0x22, 0x72, 0xf2, 0xcd, 0xaf, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xf8, 0xd7, 0x14, 0x95, 0x57, 0x03, 0x00, 0x00, } func (m *IPAddress) Marshal() (dAtA []byte, err error) { diff --git a/src/runtime/virtcontainers/pkg/cgroups/manager.go b/src/runtime/virtcontainers/pkg/cgroups/manager.go index 9c8dbb9bc0d4..2d955de5cdf3 100644 --- a/src/runtime/virtcontainers/pkg/cgroups/manager.go +++ b/src/runtime/virtcontainers/pkg/cgroups/manager.go @@ -8,6 +8,7 @@ package cgroups import ( "bufio" "context" + "errors" "fmt" "io/ioutil" "os" @@ -17,9 +18,9 @@ import ( "sync" "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/rootless" + "github.com/opencontainers/runc/libcontainer" libcontcgroups "github.com/opencontainers/runc/libcontainer/cgroups" libcontcgroupsfs "github.com/opencontainers/runc/libcontainer/cgroups/fs" - libcontcgroupssystemd "github.com/opencontainers/runc/libcontainer/cgroups/systemd" "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/specconv" "github.com/opencontainers/runtime-spec/specs-go" @@ -131,7 +132,7 @@ func New(config *Config) (*Manager, error) { UseSystemdCgroup: useSystemdCgroup, Spec: &newSpec, RootlessCgroups: rootless, - }); err != nil { + }, nil); err != nil { return nil, fmt.Errorf("Could not create cgroup config: %v", err) } } @@ -144,22 +145,28 @@ func New(config *Config) (*Manager, error) { } if useSystemdCgroup { - systemdCgroupFunc, err := libcontcgroupssystemd.NewSystemdCgroupsManager() + factory, err := libcontainer.New("") + if err != nil { + return nil, fmt.Errorf("Could not create linux factory for systemd cgroup manager: %v", err) + } + lfactory, ok := factory.(*libcontainer.LinuxFactory) + if !ok { + return nil, errors.New("expected linux factory returned on linux based systems") + } + + err = libcontainer.SystemdCgroups(lfactory) + if err != nil { return nil, fmt.Errorf("Could not create systemd cgroup manager: %v", err) } - libcontcgroupssystemd.UseSystemd() + return &Manager{ - mgr: systemdCgroupFunc(cgroups, cgroupPaths), + mgr: lfactory.NewCgroupsManager(cgroups, cgroupPaths), }, nil } return &Manager{ - mgr: &libcontcgroupsfs.Manager{ - Cgroups: cgroups, - Rootless: rootless, - Paths: cgroupPaths, - }, + mgr: libcontcgroupsfs.NewManager(cgroups, cgroupPaths, rootless), }, nil } @@ -299,7 +306,7 @@ func (m *Manager) AddDevice(ctx context.Context, device string) error { return err } - ld, err := DeviceToCgroupDevice(device) + ld, err := DeviceToCgroupDeviceRule(device) if err != nil { return err } @@ -318,9 +325,14 @@ func (m *Manager) RemoveDevice(device string) error { return err } + ld, err := DeviceToCgroupDeviceRule(device) + if err != nil { + return err + } + m.Lock() for i, d := range cgroups.Devices { - if d.Path == device { + if d.Major == ld.Major && d.Minor == ld.Minor { cgroups.Devices = append(cgroups.Devices[:i], cgroups.Devices[i+1:]...) m.Unlock() return m.Apply() diff --git a/src/runtime/virtcontainers/pkg/cgroups/utils.go b/src/runtime/virtcontainers/pkg/cgroups/utils.go index 0086be6272f5..f5540f17308e 100644 --- a/src/runtime/virtcontainers/pkg/cgroups/utils.go +++ b/src/runtime/virtcontainers/pkg/cgroups/utils.go @@ -7,11 +7,10 @@ package cgroups import ( "fmt" - "os" "path/filepath" "strings" - "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/devices" "github.com/opencontainers/runtime-spec/specs-go" "golang.org/x/sys/unix" ) @@ -76,12 +75,11 @@ func IsSystemdCgroup(cgroupPath string) bool { return false } -func DeviceToCgroupDevice(device string) (*configs.Device, error) { +func DeviceToCgroupDeviceRule(device string) (*devices.Rule, error) { var st unix.Stat_t - linuxDevice := configs.Device{ + deviceRule := devices.Rule{ Allow: true, Permissions: "rwm", - Path: device, } if err := unix.Stat(device, &st); err != nil { @@ -92,27 +90,23 @@ func DeviceToCgroupDevice(device string) (*configs.Device, error) { switch devType { case unix.S_IFCHR: - linuxDevice.Type = 'c' + deviceRule.Type = 'c' case unix.S_IFBLK: - linuxDevice.Type = 'b' + deviceRule.Type = 'b' default: return nil, fmt.Errorf("unsupported device type: %v", devType) } major := int64(unix.Major(st.Rdev)) minor := int64(unix.Minor(st.Rdev)) - linuxDevice.Major = major - linuxDevice.Minor = minor + deviceRule.Major = major + deviceRule.Minor = minor - linuxDevice.Gid = st.Gid - linuxDevice.Uid = st.Uid - linuxDevice.FileMode = os.FileMode(st.Mode) - - return &linuxDevice, nil + return &deviceRule, nil } func DeviceToLinuxDevice(device string) (specs.LinuxDeviceCgroup, error) { - dev, err := DeviceToCgroupDevice(device) + dev, err := DeviceToCgroupDeviceRule(device) if err != nil { return specs.LinuxDeviceCgroup{}, err } @@ -122,6 +116,6 @@ func DeviceToLinuxDevice(device string) (specs.LinuxDeviceCgroup, error) { Type: string(dev.Type), Major: &dev.Major, Minor: &dev.Minor, - Access: dev.Permissions, + Access: string(dev.Permissions), }, nil } diff --git a/src/runtime/virtcontainers/pkg/cgroups/utils_test.go b/src/runtime/virtcontainers/pkg/cgroups/utils_test.go index 4203085b8207..27c7aa709a7e 100644 --- a/src/runtime/virtcontainers/pkg/cgroups/utils_test.go +++ b/src/runtime/virtcontainers/pkg/cgroups/utils_test.go @@ -105,7 +105,7 @@ func TestValidCgroupPath(t *testing.T) { } -func TestDeviceToCgroupDevice(t *testing.T) { +func TestDeviceToCgroupDeviceRule(t *testing.T) { assert := assert.New(t) f, err := ioutil.TempFile("", "device") @@ -113,13 +113,13 @@ func TestDeviceToCgroupDevice(t *testing.T) { f.Close() // fail: regular file to device - dev, err := DeviceToCgroupDevice(f.Name()) + dev, err := DeviceToCgroupDeviceRule(f.Name()) assert.Error(err) assert.Nil(dev) // fail: no such file os.Remove(f.Name()) - dev, err = DeviceToCgroupDevice(f.Name()) + dev, err = DeviceToCgroupDeviceRule(f.Name()) assert.Error(err) assert.Nil(dev) @@ -128,17 +128,13 @@ func TestDeviceToCgroupDevice(t *testing.T) { t.Skipf("no such device: %v", devPath) return } - dev, err = DeviceToCgroupDevice(devPath) + dev, err = DeviceToCgroupDeviceRule(devPath) assert.NoError(err) assert.NotNil(dev) - assert.Equal(dev.Type, 'c') - assert.Equal(dev.Path, devPath) + assert.Equal(rune(dev.Type), 'c') assert.NotZero(dev.Major) assert.NotZero(dev.Minor) assert.NotEmpty(dev.Permissions) - assert.NotZero(dev.FileMode) - assert.Zero(dev.Uid) - assert.Zero(dev.Gid) assert.True(dev.Allow) } diff --git a/src/runtime/virtcontainers/pkg/oci/utils.go b/src/runtime/virtcontainers/pkg/oci/utils.go index b007f3ae318a..2a3a4c3c1396 100644 --- a/src/runtime/virtcontainers/pkg/oci/utils.go +++ b/src/runtime/virtcontainers/pkg/oci/utils.go @@ -1086,34 +1086,6 @@ func getShmSize(c vc.ContainerConfig) (uint64, error) { return shmSize, nil } -// StatusToOCIState translates a virtcontainers container status into an OCI state. -func StatusToOCIState(status vc.ContainerStatus) specs.State { - return specs.State{ - Version: specs.Version, - ID: status.ID, - Status: StateToOCIState(status.State.State), - Pid: status.PID, - Bundle: status.Annotations[vcAnnotations.BundlePathKey], - Annotations: status.Annotations, - } -} - -// StateToOCIState translates a virtcontainers container state into an OCI one. -func StateToOCIState(state types.StateString) string { - switch state { - case types.StateReady: - return StateCreated - case types.StateRunning: - return StateRunning - case types.StateStopped: - return StateStopped - case types.StatePaused: - return StatePaused - default: - return "" - } -} - // EnvVars converts an OCI process environment variables slice // into a virtcontainers EnvVar slice. func EnvVars(envs []string) ([]types.EnvVar, error) { diff --git a/src/runtime/virtcontainers/pkg/oci/utils_test.go b/src/runtime/virtcontainers/pkg/oci/utils_test.go index 8e8a5a3ed304..a2c962912d5c 100644 --- a/src/runtime/virtcontainers/pkg/oci/utils_test.go +++ b/src/runtime/virtcontainers/pkg/oci/utils_test.go @@ -188,163 +188,6 @@ func TestMinimalSandboxConfig(t *testing.T) { assert.NoError(os.Remove(configPath)) } -func testStatusToOCIStateSuccessful(t *testing.T, cStatus vc.ContainerStatus, expected specs.State) { - ociState := StatusToOCIState(cStatus) - assert.Exactly(t, ociState, expected) -} - -func TestStatusToOCIStateSuccessfulWithReadyState(t *testing.T) { - - testContID := "testContID" - testPID := 12345 - testRootFs := "testRootFs" - - state := types.ContainerState{ - State: types.StateReady, - } - - containerAnnotations := map[string]string{ - vcAnnotations.BundlePathKey: tempBundlePath, - } - - cStatus := vc.ContainerStatus{ - ID: testContID, - State: state, - PID: testPID, - RootFs: testRootFs, - Annotations: containerAnnotations, - } - - expected := specs.State{ - Version: specs.Version, - ID: testContID, - Status: "created", - Pid: testPID, - Bundle: tempBundlePath, - Annotations: containerAnnotations, - } - - testStatusToOCIStateSuccessful(t, cStatus, expected) - -} - -func TestStatusToOCIStateSuccessfulWithRunningState(t *testing.T) { - - testContID := "testContID" - testPID := 12345 - testRootFs := "testRootFs" - - state := types.ContainerState{ - State: types.StateRunning, - } - - containerAnnotations := map[string]string{ - vcAnnotations.BundlePathKey: tempBundlePath, - } - - cStatus := vc.ContainerStatus{ - ID: testContID, - State: state, - PID: testPID, - RootFs: testRootFs, - Annotations: containerAnnotations, - } - - expected := specs.State{ - Version: specs.Version, - ID: testContID, - Status: "running", - Pid: testPID, - Bundle: tempBundlePath, - Annotations: containerAnnotations, - } - - testStatusToOCIStateSuccessful(t, cStatus, expected) - -} - -func TestStatusToOCIStateSuccessfulWithStoppedState(t *testing.T) { - testContID := "testContID" - testPID := 12345 - testRootFs := "testRootFs" - - state := types.ContainerState{ - State: types.StateStopped, - } - - containerAnnotations := map[string]string{ - vcAnnotations.BundlePathKey: tempBundlePath, - } - - cStatus := vc.ContainerStatus{ - ID: testContID, - State: state, - PID: testPID, - RootFs: testRootFs, - Annotations: containerAnnotations, - } - - expected := specs.State{ - Version: specs.Version, - ID: testContID, - Status: "stopped", - Pid: testPID, - Bundle: tempBundlePath, - Annotations: containerAnnotations, - } - - testStatusToOCIStateSuccessful(t, cStatus, expected) - -} - -func TestStatusToOCIStateSuccessfulWithNoState(t *testing.T) { - testContID := "testContID" - testPID := 12345 - testRootFs := "testRootFs" - - containerAnnotations := map[string]string{ - vcAnnotations.BundlePathKey: tempBundlePath, - } - - cStatus := vc.ContainerStatus{ - ID: testContID, - PID: testPID, - RootFs: testRootFs, - Annotations: containerAnnotations, - } - - expected := specs.State{ - Version: specs.Version, - ID: testContID, - Status: "", - Pid: testPID, - Bundle: tempBundlePath, - Annotations: containerAnnotations, - } - - testStatusToOCIStateSuccessful(t, cStatus, expected) - -} - -func TestStateToOCIState(t *testing.T) { - var state types.StateString - assert := assert.New(t) - - assert.Empty(StateToOCIState(state)) - - state = types.StateReady - assert.Equal(StateToOCIState(state), "created") - - state = types.StateRunning - assert.Equal(StateToOCIState(state), "running") - - state = types.StateStopped - assert.Equal(StateToOCIState(state), "stopped") - - state = types.StatePaused - assert.Equal(StateToOCIState(state), "paused") -} - func TestEnvVars(t *testing.T) { assert := assert.New(t) envVars := []string{"foo=bar", "TERM=xterm", "HOME=/home/foo", "TERM=\"bar\"", "foo=\"\""} diff --git a/src/runtime/virtcontainers/types/sandbox.go b/src/runtime/virtcontainers/types/sandbox.go index 447b82d89fb1..a8419be19fe1 100644 --- a/src/runtime/virtcontainers/types/sandbox.go +++ b/src/runtime/virtcontainers/types/sandbox.go @@ -28,6 +28,9 @@ const ( // StateStopped represents a sandbox/container that has been stopped. StateStopped StateString = "stopped" + + // StateCreating represents a sandbox/container that's in creating. + StateCreating StateString = "creating" ) const (