@@ -2,17 +2,6 @@ package benchspy
22
33import (
44 "context"
5- "fmt"
6- "os"
7- "regexp"
8-
9- "github.com/docker/docker/api/types/container"
10- "github.com/pkg/errors"
11- tc "github.com/testcontainers/testcontainers-go"
12- "golang.org/x/sync/errgroup"
13- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14- "k8s.io/client-go/kubernetes"
15- "k8s.io/client-go/rest"
165)
176
187type ExecutionEnvironment string
@@ -26,210 +15,13 @@ type ResourceReporter struct {
2615 // either k8s or docker
2716 ExecutionEnvironment ExecutionEnvironment `json:"execution_environment"`
2817
29- // AUT metrics
30- PodsResources map [string ]* PodResources `json:"pods_resources"`
31- ContainerResources map [string ]* DockerResources `json:"container_resources"`
3218 // regex pattern to select the resources we want to fetch
3319 ResourceSelectionPattern string `json:"resource_selection_pattern"`
3420}
3521
36- type DockerResources struct {
37- NanoCPUs int64
38- CpuShares int64
39- Memory int64
40- MemorySwap int64
41- }
42-
43- type PodResources struct {
44- RequestsCPU int64
45- RequestsMemory int64
46- LimitsCPU int64
47- LimitsMemory int64
48- }
49-
50- func (r * ResourceReporter ) FetchResources (ctx context.Context ) error {
51- if r .ExecutionEnvironment == ExecutionEnvironment_Docker {
52- err := r .fetchDockerResources (ctx )
53- if err != nil {
54- return err
55- }
56- } else {
57- err := r .fetchK8sResources (ctx )
58- if err != nil {
59- return err
60- }
61- }
62-
63- return nil
64- }
65-
66- func (r * ResourceReporter ) fetchK8sResources (ctx context.Context ) error {
67- config , err := rest .InClusterConfig ()
68- if err != nil {
69- return errors .Wrapf (err , "failed to get in-cluster config, are you sure this is running in a k8s cluster?" )
70- }
71-
72- clientset , err := kubernetes .NewForConfig (config )
73- if err != nil {
74- return errors .Wrapf (err , "failed to create k8s clientset" )
75- }
76-
77- namespaceFile := "/var/run/secrets/kubernetes.io/serviceaccount/namespace"
78- namespace , err := os .ReadFile (namespaceFile )
79- if err != nil {
80- return errors .Wrapf (err , "failed to read namespace file %s" , namespaceFile )
81- }
82-
83- pods , err := clientset .CoreV1 ().Pods (string (namespace )).List (ctx , metav1.ListOptions {})
84- if err != nil {
85- return errors .Wrapf (err , "failed to list pods in namespace %s" , namespace )
86- }
87-
88- r .PodsResources = make (map [string ]* PodResources )
89-
90- for _ , pod := range pods .Items {
91- r .PodsResources [pod .Name ] = & PodResources {
92- RequestsCPU : pod .Spec .Containers [0 ].Resources .Requests .Cpu ().MilliValue (),
93- RequestsMemory : pod .Spec .Containers [0 ].Resources .Requests .Memory ().Value (),
94- LimitsCPU : pod .Spec .Containers [0 ].Resources .Limits .Cpu ().MilliValue (),
95- LimitsMemory : pod .Spec .Containers [0 ].Resources .Limits .Memory ().Value (),
96- }
97- }
98-
99- return nil
100- }
101-
102- func (r * ResourceReporter ) fetchDockerResources (ctx context.Context ) error {
103- provider , err := tc .NewDockerProvider ()
104- if err != nil {
105- return fmt .Errorf ("failed to create Docker provider: %w" , err )
106- }
107-
108- containers , err := provider .Client ().ContainerList (ctx , container.ListOptions {All : true })
109- if err != nil {
110- return fmt .Errorf ("failed to list Docker containers: %w" , err )
111- }
112-
113- eg , errCtx := errgroup .WithContext (ctx )
114- pattern := regexp .MustCompile (r .ResourceSelectionPattern )
115-
116- resultCh := make (chan map [string ]* DockerResources , len (containers ))
117-
118- for _ , containerInfo := range containers {
119- eg .Go (func () error {
120- containerName := containerInfo .Names [0 ]
121- if ! pattern .Match ([]byte (containerName )) {
122- return nil
123- }
124-
125- info , err := provider .Client ().ContainerInspect (errCtx , containerInfo .ID )
126- if err != nil {
127- return errors .Wrapf (err , "failed to inspect container %s" , containerName )
128- }
129-
130- result := make (map [string ]* DockerResources )
131- result [containerName ] = & DockerResources {
132- NanoCPUs : info .HostConfig .NanoCPUs ,
133- CpuShares : info .HostConfig .CPUShares ,
134- Memory : info .HostConfig .Memory ,
135- MemorySwap : info .HostConfig .MemorySwap ,
136- }
137-
138- select {
139- case resultCh <- result :
140- return nil
141- case <- errCtx .Done ():
142- return errCtx .Err () // Allows goroutine to exit if timeout occurs
143- }
144- })
145- }
146-
147- if err := eg .Wait (); err != nil {
148- return errors .Wrapf (err , "failed to fetch Docker resources" )
149- }
150-
151- r .ContainerResources = make (map [string ]* DockerResources )
152-
153- for i := 0 ; i < len (containers ); i ++ {
154- result := <- resultCh
155- for name , res := range result {
156- r .ContainerResources [name ] = res
157- }
158- }
159-
160- return nil
161- }
162-
163- func (r * ResourceReporter ) CompareResources (other * ResourceReporter ) error {
164- if r .ExecutionEnvironment != other .ExecutionEnvironment {
165- return fmt .Errorf ("execution environments are different. Expected %s, got %s" , r .ExecutionEnvironment , other .ExecutionEnvironment )
166- }
167-
168- if r .ExecutionEnvironment == ExecutionEnvironment_Docker {
169- return r .compareDockerResources (other .ContainerResources )
170- }
171-
172- return r .comparePodResources (other .PodsResources )
173- }
174-
175- func (r * ResourceReporter ) comparePodResources (other map [string ]* PodResources ) error {
176- this := r .PodsResources
177- if len (this ) != len (other ) {
178- return fmt .Errorf ("pod resources count is different. Expected %d, got %d" , len (this ), len (other ))
179- }
180-
181- for name1 , res1 := range this {
182- if res2 , ok := other [name1 ]; ! ok {
183- return fmt .Errorf ("pod resource %s is missing from the other report" , name1 )
184- } else {
185- if res1 == nil {
186- return fmt .Errorf ("pod resource %s is nil in the current report" , name1 )
187- }
188- if res2 == nil {
189- return fmt .Errorf ("pod resource %s is nil in the other report" , name1 )
190- }
191- if * res1 != * res2 {
192- return fmt .Errorf ("pod resource %s is different. Expected %v, got %v" , name1 , res1 , res2 )
193- }
194- }
195- }
196-
197- for name2 := range other {
198- if _ , ok := this [name2 ]; ! ok {
199- return fmt .Errorf ("pod resource %s is missing from the current report" , name2 )
200- }
201- }
202-
203- return nil
204- }
205-
206- func (r * ResourceReporter ) compareDockerResources (other map [string ]* DockerResources ) error {
207- this := r .ContainerResources
208- if len (this ) != len (other ) {
209- return fmt .Errorf ("container resources count is different. Expected %d, got %d" , len (this ), len (other ))
210- }
211-
212- for name1 , res1 := range this {
213- if res2 , ok := other [name1 ]; ! ok {
214- return fmt .Errorf ("container resource %s is missing from the other report" , name1 )
215- } else {
216- if res1 == nil {
217- return fmt .Errorf ("container resource %s is nil in the current report" , name1 )
218- }
219- if res2 == nil {
220- return fmt .Errorf ("container resource %s is nil in the other report" , name1 )
221- }
222- if * res1 != * res2 {
223- return fmt .Errorf ("container resource %s is different. Expected %v, got %v" , name1 , res1 , res2 )
224- }
225- }
226- }
227-
228- for name2 := range other {
229- if _ , ok := this [name2 ]; ! ok {
230- return fmt .Errorf ("container resource %s is missing from the current report" , name2 )
231- }
232- }
22+ func (r * ResourceReporter ) FetchResources (_ context.Context ) error {
23+ // for k8s we should query Prometheus to get the CPU and mem usage (median, min, max)
24+ // for Docker we need to wait for @Sergey to add a container that will expose historical CPU and mem usage
23325
23426 return nil
23527}
0 commit comments