From 28e1dee3336c77bafca5b5b7b6a92a1801b3b7e7 Mon Sep 17 00:00:00 2001 From: Claudiu Belu Date: Thu, 18 Apr 2019 14:38:12 +0000 Subject: [PATCH] test images: Adds Windows support for resource-consumer stress was being used for the memory consumption part. This adds a golang equivalent, which will also work on Windows. --- test/images/resource-consumer/BASEIMAGE | 5 ++ test/images/resource-consumer/BUILD | 2 + .../resource-consumer/Dockerfile_windows | 33 ++++++++ .../resource-consumer/consume-cpu/BUILD | 55 ++++++++++++- .../resource-consumer/consume-cpu/common.go | 37 +++++++++ .../consume-cpu/consume_cpu.go | 17 +--- .../consume-cpu/consume_cpu_windows.go | 77 +++++++++++++++++++ test/images/resource-consumer/utils.go | 28 ++----- test/images/resource-consumer/utils_common.go | 42 ++++++++++ .../images/resource-consumer/utils_windows.go | 52 +++++++++++++ 10 files changed, 311 insertions(+), 37 deletions(-) create mode 100644 test/images/resource-consumer/Dockerfile_windows create mode 100644 test/images/resource-consumer/consume-cpu/common.go create mode 100644 test/images/resource-consumer/consume-cpu/consume_cpu_windows.go create mode 100644 test/images/resource-consumer/utils_common.go create mode 100644 test/images/resource-consumer/utils_windows.go diff --git a/test/images/resource-consumer/BASEIMAGE b/test/images/resource-consumer/BASEIMAGE index 277470c0baf..0f593275cfe 100644 --- a/test/images/resource-consumer/BASEIMAGE +++ b/test/images/resource-consumer/BASEIMAGE @@ -3,3 +3,8 @@ linux/arm=k8s.gcr.io/debian-base-arm:0.4.1 linux/arm64=k8s.gcr.io/debian-base-arm64:0.4.1 linux/ppc64le=k8s.gcr.io/debian-base-ppc64le:0.4.1 linux/s390x=k8s.gcr.io/debian-base-s390x:0.4.1 +windows/amd64/1809=mcr.microsoft.com/windows/nanoserver:1809 +windows/amd64/1903=mcr.microsoft.com/windows/nanoserver:1903 +windows/amd64/1909=mcr.microsoft.com/windows/nanoserver:1909 +windows/amd64/2004=mcr.microsoft.com/windows/nanoserver:2004 +windows/amd64/20H2=mcr.microsoft.com/windows/nanoserver:20H2 diff --git a/test/images/resource-consumer/BUILD b/test/images/resource-consumer/BUILD index 2c28fce13ac..cdab0d06c34 100644 --- a/test/images/resource-consumer/BUILD +++ b/test/images/resource-consumer/BUILD @@ -17,6 +17,8 @@ go_library( "resource_consumer.go", "resource_consumer_handler.go", "utils.go", + "utils_common.go", + "utils_windows.go", ], importpath = "k8s.io/kubernetes/test/images/resource-consumer", deps = ["//test/images/resource-consumer/common:go_default_library"], diff --git a/test/images/resource-consumer/Dockerfile_windows b/test/images/resource-consumer/Dockerfile_windows new file mode 100644 index 00000000000..04ae81c642d --- /dev/null +++ b/test/images/resource-consumer/Dockerfile_windows @@ -0,0 +1,33 @@ +# Copyright 2021 The Kubernetes Authors. +# +# 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. + +ARG BASEIMAGE + +# We're using a Linux image to unpack the archives, then we're copying them over to Windows. +FROM --platform=linux/amd64 alpine:3.6 as prep + +ADD https://download.sysinternals.com/files/Testlimit.zip /Testlimit.zip +RUN unzip /Testlimit.zip -d / + +FROM $BASEIMAGE + +COPY --from=prep /Testlimit64.exe /bin/testlimit.exe +COPY --from=prep /Eula.txt /bin/ + +ADD consumer /consumer.exe +ADD consume-cpu/consume-cpu /consume-cpu/consume-cpu.exe + +ENV PATH="C:\bin\;C:\curl\;C:\Windows\system32;C:\Windows;C:\Program Files\PowerShell;" +EXPOSE 8080 +ENTRYPOINT ["/consumer.exe"] diff --git a/test/images/resource-consumer/consume-cpu/BUILD b/test/images/resource-consumer/consume-cpu/BUILD index f6671b52c5c..cad26c222f8 100644 --- a/test/images/resource-consumer/consume-cpu/BUILD +++ b/test/images/resource-consumer/consume-cpu/BUILD @@ -13,9 +13,60 @@ go_binary( go_library( name = "go_default_library", - srcs = ["consume_cpu.go"], + srcs = [ + "common.go", + "consume_cpu.go", + "consume_cpu_windows.go", + ], importpath = "k8s.io/kubernetes/test/images/resource-consumer/consume-cpu", - deps = ["//vendor/bitbucket.org/bertimus9/systemstat:go_default_library"], + deps = select({ + "@io_bazel_rules_go//go/platform:aix": [ + "//vendor/bitbucket.org/bertimus9/systemstat:go_default_library", + ], + "@io_bazel_rules_go//go/platform:android": [ + "//vendor/bitbucket.org/bertimus9/systemstat:go_default_library", + ], + "@io_bazel_rules_go//go/platform:darwin": [ + "//vendor/bitbucket.org/bertimus9/systemstat:go_default_library", + ], + "@io_bazel_rules_go//go/platform:dragonfly": [ + "//vendor/bitbucket.org/bertimus9/systemstat:go_default_library", + ], + "@io_bazel_rules_go//go/platform:freebsd": [ + "//vendor/bitbucket.org/bertimus9/systemstat:go_default_library", + ], + "@io_bazel_rules_go//go/platform:illumos": [ + "//vendor/bitbucket.org/bertimus9/systemstat:go_default_library", + ], + "@io_bazel_rules_go//go/platform:ios": [ + "//vendor/bitbucket.org/bertimus9/systemstat:go_default_library", + ], + "@io_bazel_rules_go//go/platform:js": [ + "//vendor/bitbucket.org/bertimus9/systemstat:go_default_library", + ], + "@io_bazel_rules_go//go/platform:linux": [ + "//vendor/bitbucket.org/bertimus9/systemstat:go_default_library", + ], + "@io_bazel_rules_go//go/platform:nacl": [ + "//vendor/bitbucket.org/bertimus9/systemstat:go_default_library", + ], + "@io_bazel_rules_go//go/platform:netbsd": [ + "//vendor/bitbucket.org/bertimus9/systemstat:go_default_library", + ], + "@io_bazel_rules_go//go/platform:openbsd": [ + "//vendor/bitbucket.org/bertimus9/systemstat:go_default_library", + ], + "@io_bazel_rules_go//go/platform:plan9": [ + "//vendor/bitbucket.org/bertimus9/systemstat:go_default_library", + ], + "@io_bazel_rules_go//go/platform:solaris": [ + "//vendor/bitbucket.org/bertimus9/systemstat:go_default_library", + ], + "@io_bazel_rules_go//go/platform:windows": [ + "//vendor/golang.org/x/sys/windows:go_default_library", + ], + "//conditions:default": [], + }), ) filegroup( diff --git a/test/images/resource-consumer/consume-cpu/common.go b/test/images/resource-consumer/consume-cpu/common.go new file mode 100644 index 00000000000..e99c03378a7 --- /dev/null +++ b/test/images/resource-consumer/consume-cpu/common.go @@ -0,0 +1,37 @@ +/* +Copyright 2021 The Kubernetes Authors. + +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. +*/ + +package main + +import ( + "flag" + "math" + "time" +) + +const sleep = time.Duration(10) * time.Millisecond + +func doSomething() { + for i := 1; i < 10000000; i++ { + x := float64(0) + x += math.Sqrt(0) + } +} + +var ( + millicores = flag.Int("millicores", 0, "millicores number") + durationSec = flag.Int("duration-sec", 0, "duration time in seconds") +) diff --git a/test/images/resource-consumer/consume-cpu/consume_cpu.go b/test/images/resource-consumer/consume-cpu/consume_cpu.go index 08a6dc98667..c8ac71b76c6 100644 --- a/test/images/resource-consumer/consume-cpu/consume_cpu.go +++ b/test/images/resource-consumer/consume-cpu/consume_cpu.go @@ -1,3 +1,5 @@ +// +build !windows + /* Copyright 2015 The Kubernetes Authors. @@ -18,26 +20,11 @@ package main import ( "flag" - "math" "time" "bitbucket.org/bertimus9/systemstat" ) -const sleep = time.Duration(10) * time.Millisecond - -func doSomething() { - for i := 1; i < 10000000; i++ { - x := float64(0) - x += math.Sqrt(0) - } -} - -var ( - millicores = flag.Int("millicores", 0, "millicores number") - durationSec = flag.Int("duration-sec", 0, "duration time in seconds") -) - func main() { flag.Parse() // convert millicores to percentage diff --git a/test/images/resource-consumer/consume-cpu/consume_cpu_windows.go b/test/images/resource-consumer/consume-cpu/consume_cpu_windows.go new file mode 100644 index 00000000000..d9ea44b7ac8 --- /dev/null +++ b/test/images/resource-consumer/consume-cpu/consume_cpu_windows.go @@ -0,0 +1,77 @@ +// +build windows + +/* +Copyright 2021 The Kubernetes Authors. + +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. +*/ + +package main + +import ( + "flag" + "syscall" + "time" + + syswin "golang.org/x/sys/windows" +) + +type procCPUStats struct { + User int64 // nanoseconds spent in user mode + System int64 // nanoseconds spent in system mode + Time time.Time // when the sample was taken + Total int64 // total of all time fields (nanoseconds) +} + +// Retrieves the amount of CPU time this process has used since it started. +func statsNow(handle syscall.Handle) (s procCPUStats) { + var processInfo syscall.Rusage + syscall.GetProcessTimes(handle, &processInfo.CreationTime, &processInfo.ExitTime, &processInfo.KernelTime, &processInfo.UserTime) + s.Time = time.Now() + s.User = processInfo.UserTime.Nanoseconds() + s.System = processInfo.KernelTime.Nanoseconds() + s.Total = s.User + s.System + return s +} + +// Given stats from two time points, calculates the millicores used by this +// process between the two samples. +func usageNow(first procCPUStats, second procCPUStats) int64 { + dT := second.Time.Sub(first.Time).Nanoseconds() + dUsage := (second.Total - first.Total) + if dT == 0 { + return 0 + } + return 1000 * dUsage / dT +} + +func main() { + flag.Parse() + phandle, err := syswin.GetCurrentProcess() + if err != nil { + panic(err) + } + handle := syscall.Handle(phandle) + + duration := time.Duration(*durationSec) * time.Second + start := time.Now() + first := statsNow(handle) + for time.Since(start) < duration { + currentMillicores := usageNow(first, statsNow(handle)) + if currentMillicores < int64(*millicores) { + doSomething() + } else { + time.Sleep(sleep) + } + } +} diff --git a/test/images/resource-consumer/utils.go b/test/images/resource-consumer/utils.go index 64ea8838c72..dcd0b9ec922 100644 --- a/test/images/resource-consumer/utils.go +++ b/test/images/resource-consumer/utils.go @@ -1,5 +1,7 @@ +// +build !windows + /* -Copyright 2015 The Kubernetes Authors. +Copyright 2021 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,27 +19,16 @@ limitations under the License. package main import ( - "fmt" "log" "os/exec" "strconv" ) -const ( +var ( consumeCPUBinary = "./consume-cpu/consume-cpu" consumeMemBinary = "stress" ) -// ConsumeCPU consumes a given number of millicores for the specified duration. -func ConsumeCPU(millicores int, durationSec int) { - log.Printf("ConsumeCPU millicores: %v, durationSec: %v", millicores, durationSec) - // creating new consume cpu process - arg1 := fmt.Sprintf("-millicores=%d", millicores) - arg2 := fmt.Sprintf("-duration-sec=%d", durationSec) - consumeCPU := exec.Command(consumeCPUBinary, arg1, arg2) - consumeCPU.Run() -} - // ConsumeMem consumes a given number of megabytes for the specified duration. func ConsumeMem(megabytes int, durationSec int) { log.Printf("ConsumeMem megabytes: %v, durationSec: %v", megabytes, durationSec) @@ -45,11 +36,8 @@ func ConsumeMem(megabytes int, durationSec int) { durationSecString := strconv.Itoa(durationSec) // creating new consume memory process consumeMem := exec.Command(consumeMemBinary, "-m", "1", "--vm-bytes", megabytesString, "--vm-hang", "0", "-t", durationSecString) - consumeMem.Run() -} - -// GetCurrentStatus prints out a no-op. -func GetCurrentStatus() { - log.Printf("GetCurrentStatus") - // not implemented + err := consumeMem.Run() + if err != nil { + log.Printf("Error while consuming memory: %v", err) + } } diff --git a/test/images/resource-consumer/utils_common.go b/test/images/resource-consumer/utils_common.go new file mode 100644 index 00000000000..d6e82f25e84 --- /dev/null +++ b/test/images/resource-consumer/utils_common.go @@ -0,0 +1,42 @@ +/* +Copyright 2015 The Kubernetes Authors. + +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. +*/ + +package main + +import ( + "fmt" + "log" + "os/exec" +) + +// ConsumeCPU consumes a given number of millicores for the specified duration. +func ConsumeCPU(millicores int, durationSec int) { + log.Printf("ConsumeCPU millicores: %v, durationSec: %v", millicores, durationSec) + // creating new consume cpu process + arg1 := fmt.Sprintf("-millicores=%d", millicores) + arg2 := fmt.Sprintf("-duration-sec=%d", durationSec) + consumeCPU := exec.Command(consumeCPUBinary, arg1, arg2) + err := consumeCPU.Run() + if err != nil { + log.Printf("Error while consuming CPU: %v", err) + } +} + +// GetCurrentStatus prints out a no-op. +func GetCurrentStatus() { + log.Printf("GetCurrentStatus") + // not implemented +} diff --git a/test/images/resource-consumer/utils_windows.go b/test/images/resource-consumer/utils_windows.go new file mode 100644 index 00000000000..25b66d995d4 --- /dev/null +++ b/test/images/resource-consumer/utils_windows.go @@ -0,0 +1,52 @@ +// +build windows + +/* +Copyright 2021 The Kubernetes Authors. + +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. +*/ + +package main + +import ( + "log" + "os/exec" + "strconv" + "time" +) + +var ( + consumeCPUBinary = "./consume-cpu/consume-cpu.exe" + consumeMemBinary = "testlimit.exe" +) + +// ConsumeMem consumes a given number of megabytes for the specified duration. +func ConsumeMem(megabytes int, durationSec int) { + log.Printf("ConsumeMem megabytes: %v, durationSec: %v", megabytes, durationSec) + megabytesString := strconv.Itoa(megabytes) + durationSecString := strconv.Itoa(durationSec) + // creating new consume memory process + consumeMem := exec.Command(consumeMemBinary, "-accepteula", "-r", megabytesString, "-e", "0", durationSecString, "-c", "1") + err := consumeMem.Start() + if err != nil { + log.Printf("Error while consuming memory: %v", err) + return + } + + // testlimit does not end after durationSec elapsed, so we'll stop it ourselves. + time.AfterFunc(time.Duration(durationSec)*time.Second, func() { + if err := consumeMem.Process.Kill(); err != nil { + log.Printf("Could not kill testlimit process! Error: %v", err) + } + }) +}