From 2ab75f31a003021e691c0d51c61069a6b4500261 Mon Sep 17 00:00:00 2001 From: Roger Coll Date: Wed, 18 Dec 2024 08:32:37 +0100 Subject: [PATCH] [chore] Add extension/cgroupruntime integration tests (#36617) #### Description Adds some integration tests for the extension. It uses the `containerd/cgroups` package to modify the current process's allocated cgroup resources and assert the corresponding values for GOMEMLIMIT/GOMAXPROCS set by the extension. #### Link to tracking issue Fixes https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/36545 #### Testing Cgroup resources modification requires privileged access in GHA runner instances, thus the test must be run with `sudo`. The `go` toolchain has an `exec` flag to run tests binary(s) via another binary such as sudo. The Makefile has been modified to run Go tests files with build tag `integration` && `sudo` with the sudo command. I am not very confident with this solution, as I could not find any other component requiring privileged execution for its integration tests and the "go test -tags=integration,sudo" would run for all of them. I am all ears on other testing strategies for this use case. Similar strategy in cgroups package https://github.com/containerd/cgroups/blob/main/.github/workflows/ci.yml#L101 #### Documentation --------- Co-authored-by: Pablo Baeyens --- Makefile.Common | 7 +- extension/cgroupruntimeextension/go.mod | 14 +- extension/cgroupruntimeextension/go.sum | 30 ++- .../integration_test.go | 235 ++++++++++++++++++ 4 files changed, 264 insertions(+), 22 deletions(-) create mode 100644 extension/cgroupruntimeextension/integration_test.go diff --git a/Makefile.Common b/Makefile.Common index 3b742e42a2ba..b8f2bb59913d 100644 --- a/Makefile.Common +++ b/Makefile.Common @@ -29,9 +29,11 @@ GO_BUILD_TAGS="" GO_BUILD_LDFLAGS="-s -w" GOTEST_TIMEOUT?= 600s GOTEST_OPT?= -race -timeout $(GOTEST_TIMEOUT) -parallel 4 --tags=$(GO_BUILD_TAGS) -GOTEST_INTEGRATION_OPT?= -race -timeout 360s -parallel 4 +GOTEST_INTEGRATION_OPT?= -race -timeout 360s -parallel 4 -skip Sudo +GOTEST_INTEGRATION_OPT_SUDO= $(GOTEST_INTEGRATION_OPT) -exec sudo -run Sudo GOTEST_OPT_WITH_COVERAGE = $(GOTEST_OPT) -coverprofile=coverage.txt -covermode=atomic GOTEST_OPT_WITH_INTEGRATION=$(GOTEST_INTEGRATION_OPT) -tags=integration,$(GO_BUILD_TAGS) +GOTEST_OPT_WITH_INTEGRATION_SUDO=$(GOTEST_INTEGRATION_OPT_SUDO) -tags=integration,$(GO_BUILD_TAGS) GOTEST_OPT_WITH_INTEGRATION_COVERAGE=$(GOTEST_OPT_WITH_INTEGRATION) -coverprofile=integration-coverage.txt -covermode=atomic GOCMD?= go GOOS=$(shell $(GOCMD) env GOOS) @@ -152,12 +154,13 @@ endif runbuilttest: $(GOTESTSUM) ifneq (,$(wildcard ./builtunitetest.test)) $(GOTESTSUM) --raw-command -- $(GOCMD) tool test2json -p "./..." -t ./builtunitetest.test -test.v -test.failfast -test.timeout $(GOTEST_TIMEOUT) -endif +endif .PHONY: mod-integration-test mod-integration-test: $(GOTESTSUM) @echo "running $(GOCMD) integration test ./... in `pwd`" $(GOTESTSUM) $(GOTESTSUM_OPT) --packages="./..." -- $(GOTEST_OPT_WITH_INTEGRATION) + $(GOTESTSUM) $(GOTESTSUM_OPT) --packages="./..." -- $(GOTEST_OPT_WITH_INTEGRATION_SUDO) @if [ -e integration-coverage.txt ]; then \ $(GOCMD) tool cover -html=integration-coverage.txt -o integration-coverage.html; \ fi diff --git a/extension/cgroupruntimeextension/go.mod b/extension/cgroupruntimeextension/go.mod index 5885af88a4eb..33159197c5bc 100644 --- a/extension/cgroupruntimeextension/go.mod +++ b/extension/cgroupruntimeextension/go.mod @@ -4,6 +4,7 @@ go 1.22.0 require ( github.com/KimMachineGun/automemlimit v0.6.1 + github.com/containerd/cgroups/v3 v3.0.2 github.com/stretchr/testify v1.10.0 go.opentelemetry.io/collector/component v0.116.0 go.opentelemetry.io/collector/component/componenttest v0.116.0 @@ -13,18 +14,18 @@ require ( go.uber.org/automaxprocs v1.6.0 go.uber.org/goleak v1.3.0 go.uber.org/zap v1.27.0 + golang.org/x/sys v0.27.0 ) require ( github.com/cilium/ebpf v0.9.1 // indirect - github.com/containerd/cgroups/v3 v3.0.1 // indirect - github.com/coreos/go-systemd/v22 v22.3.2 // indirect + github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/docker/go-units v0.4.0 // indirect + github.com/docker/go-units v0.5.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.2.1 // indirect - github.com/godbus/dbus/v5 v5.0.4 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/uuid v1.6.0 // indirect github.com/knadh/koanf/maps v0.1.1 // indirect @@ -32,10 +33,10 @@ require ( github.com/knadh/koanf/v2 v2.1.2 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect - github.com/opencontainers/runtime-spec v1.0.2 // indirect + github.com/opencontainers/runtime-spec v1.1.0 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/sirupsen/logrus v1.8.1 // indirect + github.com/sirupsen/logrus v1.9.0 // indirect go.opentelemetry.io/collector/config/configtelemetry v0.116.0 // indirect go.opentelemetry.io/collector/pdata v1.22.0 // indirect go.opentelemetry.io/otel v1.32.0 // indirect @@ -45,7 +46,6 @@ require ( go.opentelemetry.io/otel/trace v1.32.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/net v0.29.0 // indirect - golang.org/x/sys v0.27.0 // indirect golang.org/x/text v0.18.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect google.golang.org/grpc v1.68.1 // indirect diff --git a/extension/cgroupruntimeextension/go.sum b/extension/cgroupruntimeextension/go.sum index f9bdfad7584e..1fed12195a6d 100644 --- a/extension/cgroupruntimeextension/go.sum +++ b/extension/cgroupruntimeextension/go.sum @@ -2,14 +2,15 @@ github.com/KimMachineGun/automemlimit v0.6.1 h1:ILa9j1onAAMadBsyyUJv5cack8Y1WT26 github.com/KimMachineGun/automemlimit v0.6.1/go.mod h1:T7xYht7B8r6AG/AqFcUdc7fzd2bIdBKmepfP2S1svPY= github.com/cilium/ebpf v0.9.1 h1:64sn2K3UKw8NbP/blsixRpF3nXuyhz/VjRlRzvlBRu4= github.com/cilium/ebpf v0.9.1/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnxUFY= -github.com/containerd/cgroups/v3 v3.0.1 h1:4hfGvu8rfGIwVIDd+nLzn/B9ZXx4BcCjzt5ToenJRaE= -github.com/containerd/cgroups/v3 v3.0.1/go.mod h1:/vtwk1VXrtoa5AaZLkypuOJgA/6DyPMZHJPGQNtlHnw= -github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/containerd/cgroups/v3 v3.0.2 h1:f5WFqIVSgo5IZmtTT3qVBo6TzI1ON6sycSBKkymb9L0= +github.com/containerd/cgroups/v3 v3.0.2/go.mod h1:JUgITrzdFqp42uI2ryGA+ge0ap/nxzYgkGmIcetmErE= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -19,8 +20,9 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= @@ -45,8 +47,8 @@ github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa1 github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= -github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg= +github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -55,9 +57,10 @@ github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4 github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -110,8 +113,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -135,5 +138,6 @@ google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojt gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/extension/cgroupruntimeextension/integration_test.go b/extension/cgroupruntimeextension/integration_test.go new file mode 100644 index 000000000000..64d79c63d47c --- /dev/null +++ b/extension/cgroupruntimeextension/integration_test.go @@ -0,0 +1,235 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 +//go:build integration && linux +// +build integration,linux + +// Privileged access is required to set cgroup's memory and cpu max values + +package cgroupruntimeextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/cgroupruntimeextension" + +import ( + "context" + "fmt" + "math" + "os" + "path" + "path/filepath" + "runtime" + "runtime/debug" + "strconv" + "strings" + "testing" + + "github.com/containerd/cgroups/v3/cgroup2" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/extension/extensiontest" + "golang.org/x/sys/unix" +) + +const ( + defaultCgroup2Path = "/sys/fs/cgroup" +) + +// checkCgroupSystem skips the test if is not run in a cgroupv2 system +func checkCgroupSystem(tb testing.TB) { + var st unix.Statfs_t + err := unix.Statfs(defaultCgroup2Path, &st) + if err != nil { + tb.Skip("cannot statfs cgroup root") + } + + isUnified := st.Type == unix.CGROUP2_SUPER_MAGIC + if !isUnified { + tb.Skip("System running in hybrid or cgroupv1 mode") + } +} + +// cgroupMaxCpu returns the CPU max definition for a given cgroup slice path +// File format: cpu_quote cpu_period +func cgroupMaxCpu(filename string) (quota int64, period uint64, err error) { + out, err := os.ReadFile(filepath.Join(defaultCgroup2Path, filename, "cpu.max")) + if err != nil { + return 0, 0, err + } + values := strings.Split(strings.TrimSpace(string(out)), " ") + if values[0] == "max" { + quota = math.MaxInt64 + } else { + quota, _ = strconv.ParseInt(values[0], 10, 64) + } + period, _ = strconv.ParseUint(values[1], 10, 64) + return quota, period, err +} + +func TestCgroupV2SudoIntegration(t *testing.T) { + checkCgroupSystem(t) + pointerInt64 := func(val int64) *int64 { + return &val + } + pointerUint64 := func(uval uint64) *uint64 { + return &uval + } + + tests := []struct { + name string + // nil CPU quota == "max" cgroup string value + cgroupCpuQuota *int64 + cgroupCpuPeriod uint64 + cgroupMaxMemory int64 + config *Config + expectedGoMaxProcs int + expectedGoMemLimit int64 + }{ + { + name: "90% the max cgroup memory and 12 GOMAXPROCS", + cgroupCpuQuota: pointerInt64(100000), + cgroupCpuPeriod: 8000, + // 128 Mb + cgroupMaxMemory: 134217728, + config: &Config{ + GoMaxProcs: GoMaxProcsConfig{ + Enabled: true, + }, + GoMemLimit: GoMemLimitConfig{ + Enabled: true, + Ratio: 0.9, + }, + }, + // 100000 / 8000 + expectedGoMaxProcs: 12, + // 134217728 * 0.9 + expectedGoMemLimit: 120795955, + }, + { + name: "50% of the max cgroup memory and 1 GOMAXPROCS", + cgroupCpuQuota: pointerInt64(100000), + cgroupCpuPeriod: 100000, + // 128 Mb + cgroupMaxMemory: 134217728, + config: &Config{ + GoMaxProcs: GoMaxProcsConfig{ + Enabled: true, + }, + GoMemLimit: GoMemLimitConfig{ + Enabled: true, + Ratio: 0.5, + }, + }, + // 100000 / 100000 + expectedGoMaxProcs: 1, + // 134217728 * 0.5 + expectedGoMemLimit: 67108864, + }, + { + name: "10% of the max cgroup memory, max cpu, default GOMAXPROCS", + cgroupCpuQuota: nil, + cgroupCpuPeriod: 100000, + // 128 Mb + cgroupMaxMemory: 134217728, + config: &Config{ + GoMaxProcs: GoMaxProcsConfig{ + Enabled: true, + }, + GoMemLimit: GoMemLimitConfig{ + Enabled: true, + Ratio: 0.1, + }, + }, + // GOMAXPROCS is set to the value of `cpu.max / cpu.period` + // If cpu.max is set to max, GOMAXPROCS should not be + // modified + expectedGoMaxProcs: runtime.GOMAXPROCS(-1), + // 134217728 * 0.1 + expectedGoMemLimit: 13421772, + }, + } + + cgroupPath, err := cgroup2.PidGroupPath(os.Getpid()) + assert.NoError(t, err) + manager, err := cgroup2.Load(cgroupPath) + assert.NoError(t, err) + + stats, err := manager.Stat() + require.NoError(t, err) + + // Startup resource values + initialMaxMemory := stats.GetMemory().GetUsageLimit() + memoryCgroupCleanUp := func() { + err = manager.Update(&cgroup2.Resources{ + Memory: &cgroup2.Memory{ + Max: pointerInt64(int64(initialMaxMemory)), + }, + }) + assert.NoError(t, err) + } + + if initialMaxMemory == math.MaxUint64 { + // fallback solution to set cgroup's max memory to "max" + memoryCgroupCleanUp = func() { + err = os.WriteFile(path.Join(defaultCgroup2Path, cgroupPath, "memory.max"), []byte("max"), 0o600) + assert.NoError(t, err) + } + } + + initialCpuQuota, initialCpuPeriod, err := cgroupMaxCpu(cgroupPath) + require.NoError(t, err) + cpuCgroupCleanUp := func() { + fmt.Println(initialCpuQuota) + err = manager.Update(&cgroup2.Resources{ + CPU: &cgroup2.CPU{ + Max: cgroup2.NewCPUMax(pointerInt64(initialCpuQuota), pointerUint64(initialCpuPeriod)), + }, + }) + assert.NoError(t, err) + } + + if initialCpuQuota == math.MaxInt64 { + // fallback solution to set cgroup's max cpu to "max" + cpuCgroupCleanUp = func() { + err = os.WriteFile(path.Join(defaultCgroup2Path, cgroupPath, "cpu.max"), []byte("max"), 0o600) + assert.NoError(t, err) + } + } + + initialGoMem := debug.SetMemoryLimit(-1) + initialGoProcs := runtime.GOMAXPROCS(-1) + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + // restore startup cgroup initial resource values + t.Cleanup(func() { + debug.SetMemoryLimit(initialGoMem) + runtime.GOMAXPROCS(initialGoProcs) + memoryCgroupCleanUp() + cpuCgroupCleanUp() + }) + + err = manager.Update(&cgroup2.Resources{ + Memory: &cgroup2.Memory{ + // Default max memory must be + // overwritten + // to automemlimit change the GOMEMLIMIT + // value + Max: pointerInt64(test.cgroupMaxMemory), + }, + CPU: &cgroup2.CPU{ + Max: cgroup2.NewCPUMax(test.cgroupCpuQuota, pointerUint64(test.cgroupCpuPeriod)), + }, + }) + require.NoError(t, err) + + factory := NewFactory() + ctx := context.Background() + extension, err := factory.Create(ctx, extensiontest.NewNopSettings(), test.config) + require.NoError(t, err) + + err = extension.Start(ctx, componenttest.NewNopHost()) + require.NoError(t, err) + + assert.Equal(t, test.expectedGoMaxProcs, runtime.GOMAXPROCS(-1)) + assert.Equal(t, test.expectedGoMemLimit, debug.SetMemoryLimit(-1)) + }) + } +}