github.com/kubewharf/katalyst-core@v0.5.3/pkg/agent/resourcemanager/fetcher/kubelet/kubeletplugin_test.go (about) 1 /* 2 Copyright 2022 The Katalyst Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package kubelet 18 19 import ( 20 "context" 21 "io/ioutil" 22 "net" 23 "os" 24 "path" 25 "testing" 26 "time" 27 28 info "github.com/google/cadvisor/info/v1" 29 "github.com/stretchr/testify/assert" 30 "google.golang.org/grpc" 31 v1 "k8s.io/api/core/v1" 32 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 33 "k8s.io/klog/v2" 34 kubeletconfigv1beta1 "k8s.io/kubelet/config/v1beta1" 35 podresv1 "k8s.io/kubelet/pkg/apis/podresources/v1" 36 apisconfig "k8s.io/kubernetes/pkg/kubelet/apis/config" 37 "k8s.io/kubernetes/pkg/kubelet/checkpointmanager" 38 testutil "k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/state/testing" 39 40 "github.com/kubewharf/katalyst-api/pkg/consts" 41 "github.com/kubewharf/katalyst-api/pkg/protocol/reporterplugin/v1alpha1" 42 "github.com/kubewharf/katalyst-core/cmd/katalyst-agent/app/options" 43 "github.com/kubewharf/katalyst-core/pkg/agent/resourcemanager/fetcher/kubelet/topology" 44 "github.com/kubewharf/katalyst-core/pkg/config" 45 pkgconsts "github.com/kubewharf/katalyst-core/pkg/consts" 46 "github.com/kubewharf/katalyst-core/pkg/metaserver" 47 "github.com/kubewharf/katalyst-core/pkg/metaserver/agent" 48 "github.com/kubewharf/katalyst-core/pkg/metaserver/agent/kubeletconfig" 49 "github.com/kubewharf/katalyst-core/pkg/metaserver/agent/pod" 50 "github.com/kubewharf/katalyst-core/pkg/metrics" 51 "github.com/kubewharf/katalyst-core/pkg/util/machine" 52 ) 53 54 type fakePodResourcesServer struct { 55 podResources *podresv1.ListPodResourcesResponse 56 allocatableResources *podresv1.AllocatableResourcesResponse 57 podresv1.UnimplementedPodResourcesListerServer 58 } 59 60 func (m *fakePodResourcesServer) List(_ context.Context, _ *podresv1.ListPodResourcesRequest) (*podresv1.ListPodResourcesResponse, error) { 61 return m.podResources, nil 62 } 63 64 func (m *fakePodResourcesServer) GetAllocatableResources(_ context.Context, _ *podresv1.AllocatableResourcesRequest) (*podresv1.AllocatableResourcesResponse, error) { 65 return m.allocatableResources, nil 66 } 67 68 func newFakePodResourcesServer(podResources *podresv1.ListPodResourcesResponse, allocatableResources *podresv1.AllocatableResourcesResponse) *grpc.Server { 69 server := grpc.NewServer() 70 podresv1.RegisterPodResourcesListerServer(server, &fakePodResourcesServer{ 71 podResources: podResources, 72 allocatableResources: allocatableResources, 73 }) 74 return server 75 } 76 77 func generateTestConfiguration(t *testing.T, dir string) *config.Configuration { 78 testConfiguration, err := options.NewOptions().Config() 79 assert.NoError(t, err) 80 assert.NotNil(t, testConfiguration) 81 82 testConfiguration.PodResourcesServerEndpoints = []string{ 83 path.Join(dir, "podresources.sock"), 84 } 85 testConfiguration.KubeletResourcePluginPaths = []string{ 86 path.Join(dir, "resource-plugins/"), 87 } 88 return testConfiguration 89 } 90 91 func generateTestMetaServer(podList ...*v1.Pod) *metaserver.MetaServer { 92 fakeKubeletConfig := kubeletconfigv1beta1.KubeletConfiguration{ 93 TopologyManagerPolicy: apisconfig.SingleNumaNodeTopologyManagerPolicy, 94 TopologyManagerScope: apisconfig.ContainerTopologyManagerScope, 95 } 96 97 return &metaserver.MetaServer{ 98 MetaAgent: &agent.MetaAgent{ 99 PodFetcher: &pod.PodFetcherStub{PodList: podList}, 100 KatalystMachineInfo: &machine.KatalystMachineInfo{ 101 MachineInfo: &info.MachineInfo{ 102 Topology: []info.Node{ 103 { 104 Id: 0, 105 Cores: []info.Core{ 106 {SocketID: 0, Id: 0, Threads: []int{0, 4}}, 107 {SocketID: 0, Id: 1, Threads: []int{1, 5}}, 108 {SocketID: 0, Id: 2, Threads: []int{2, 2}}, // Wrong case - should fail here 109 {SocketID: 0, Id: 3, Threads: []int{3, 7}}, 110 }, 111 }, 112 { 113 Id: 1, 114 Cores: []info.Core{ 115 {SocketID: 1, Id: 4, Threads: []int{8, 12}}, 116 {SocketID: 1, Id: 5, Threads: []int{9, 13}}, 117 {SocketID: 1, Id: 6, Threads: []int{10, 14}}, // Wrong case - should fail here 118 {SocketID: 1, Id: 7, Threads: []int{11, 15}}, 119 }, 120 }, 121 }, 122 }, 123 }, 124 KubeletConfigFetcher: kubeletconfig.NewFakeKubeletConfigFetcher(fakeKubeletConfig), 125 }, 126 } 127 } 128 129 func tmpSocketDir() (socketDir string, err error) { 130 socketDir, err = ioutil.TempDir("", "pod_resources") 131 if err != nil { 132 return 133 } 134 err = os.MkdirAll(socketDir, 0o755) 135 if err != nil { 136 return "", err 137 } 138 return 139 } 140 141 func TestNewKubeletReporterPlugin(t *testing.T) { 142 t.Parallel() 143 144 dir, err := tmpSocketDir() 145 assert.NoError(t, err) 146 defer os.RemoveAll(dir) 147 148 conf := generateTestConfiguration(t, dir) 149 150 listener, err := net.Listen("unix", conf.PodResourcesServerEndpoints[0]) 151 if err != nil { 152 t.Fatalf("failed to create listener: %v", err) 153 } 154 155 server := newFakePodResourcesServer( 156 &podresv1.ListPodResourcesResponse{ 157 PodResources: []*podresv1.PodResources{ 158 { 159 Name: "pod-1", 160 Namespace: "default", 161 PodRole: "pod-role-1", 162 PodType: "pod-type-1", 163 Containers: []*podresv1.ContainerResources{ 164 { 165 Name: "container-1", 166 Devices: []*podresv1.ContainerDevices{ 167 { 168 ResourceName: "resource-1", 169 Topology: &podresv1.TopologyInfo{ 170 Nodes: []*podresv1.NUMANode{ 171 { 172 ID: 1, 173 }, 174 }, 175 }, 176 }, 177 }, 178 Memory: []*podresv1.ContainerMemory{ 179 { 180 MemoryType: "test", 181 Size_: 100, 182 Topology: &podresv1.TopologyInfo{ 183 Nodes: []*podresv1.NUMANode{ 184 { 185 ID: 1, 186 }, 187 }, 188 }, 189 }, 190 }, 191 Resources: []*podresv1.TopologyAwareResource{ 192 { 193 ResourceName: "cpu", 194 IsScalarResource: true, 195 TopologyAwareQuantityList: []*podresv1.TopologyAwareQuantity{ 196 { 197 ResourceValue: 10.0, 198 Node: 1, 199 }, 200 }, 201 }, 202 }, 203 }, 204 }, 205 Labels: map[string]string{ 206 "aa": "bb", 207 }, 208 Annotations: map[string]string{ 209 "aa": "bb", 210 }, 211 }, 212 }, 213 }, 214 &podresv1.AllocatableResourcesResponse{ 215 Devices: []*podresv1.ContainerDevices{ 216 { 217 ResourceName: "resource-1", 218 Topology: &podresv1.TopologyInfo{ 219 Nodes: []*podresv1.NUMANode{ 220 { 221 ID: 1, 222 }, 223 }, 224 }, 225 }, 226 }, 227 Memory: []*podresv1.ContainerMemory{ 228 { 229 MemoryType: "test", 230 Size_: 100, 231 Topology: &podresv1.TopologyInfo{ 232 Nodes: []*podresv1.NUMANode{ 233 { 234 ID: 1, 235 }, 236 }, 237 }, 238 }, 239 }, 240 Resources: []*podresv1.AllocatableTopologyAwareResource{ 241 { 242 ResourceName: "cpu", 243 IsScalarResource: true, 244 TopologyAwareAllocatableQuantityList: []*podresv1.TopologyAwareQuantity{ 245 { 246 ResourceValue: 10.0, 247 Node: 1, 248 }, 249 }, 250 }, 251 }, 252 }, 253 ) 254 255 go func() { 256 err := server.Serve(listener) 257 assert.NoError(t, err) 258 }() 259 260 meta := generateTestMetaServer(&v1.Pod{ 261 ObjectMeta: metav1.ObjectMeta{ 262 Name: "pod-1", 263 Namespace: "default", 264 UID: "pod-1-uid", 265 Annotations: map[string]string{ 266 consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelDedicatedCores, 267 consts.PodAnnotationMemoryEnhancementKey: `{"numa_binding": "true"}`, 268 }, 269 }, 270 }) 271 272 callback := func(name string, resp *v1alpha1.GetReportContentResponse) { 273 klog.Infof("Callback called with name: %s, resp: %#v", name, resp) 274 } 275 276 plugin, err := NewKubeletReporterPlugin(metrics.DummyMetrics{}, meta, conf, callback) 277 assert.NoError(t, err) 278 279 success := make(chan bool) 280 go plugin.Run(success) 281 282 <-success 283 284 checkpointManager, err := checkpointmanager.NewCheckpointManager(conf.KubeletResourcePluginPaths[0]) 285 assert.NoError(t, err) 286 287 err = checkpointManager.CreateCheckpoint(pkgconsts.KubeletQoSResourceManagerCheckpoint, &testutil.MockCheckpoint{}) 288 assert.NoError(t, err) 289 290 time.Sleep(10 * time.Millisecond) 291 plugin.Stop() 292 293 time.Sleep(10 * time.Millisecond) 294 } 295 296 func TestGetTopologyPolicyReportContent(t *testing.T) { 297 t.Parallel() 298 299 dir, err := tmpSocketDir() 300 assert.NoError(t, err) 301 defer os.RemoveAll(dir) 302 303 conf := generateTestConfiguration(t, dir) 304 conf.EnableReportTopologyPolicy = true 305 306 meta := generateTestMetaServer() 307 308 callback := func(name string, resp *v1alpha1.GetReportContentResponse) { 309 klog.Infof("Callback called with name: %s, resp: %#v", name, resp) 310 } 311 312 plugin, err := NewKubeletReporterPlugin(metrics.DummyMetrics{}, meta, conf, callback) 313 assert.NoError(t, err) 314 kubePlugin := plugin.(*kubeletPlugin) 315 316 _, err = kubePlugin.getTopologyPolicyReportContent(context.TODO()) 317 assert.NoError(t, err) 318 } 319 320 func TestGetTopologyStatusContent(t *testing.T) { 321 t.Parallel() 322 323 dir, err := tmpSocketDir() 324 assert.NoError(t, err) 325 defer os.RemoveAll(dir) 326 327 conf := generateTestConfiguration(t, dir) 328 conf.EnableReportTopologyPolicy = true 329 330 meta := generateTestMetaServer() 331 332 callback := func(name string, resp *v1alpha1.GetReportContentResponse) { 333 klog.Infof("Callback called with name: %s, resp: %#v", name, resp) 334 } 335 336 plugin, err := NewKubeletReporterPlugin(metrics.DummyMetrics{}, meta, conf, callback) 337 assert.NoError(t, err) 338 kubePlugin := plugin.(*kubeletPlugin) 339 340 kubePlugin.topologyStatusAdapter = topology.DummyAdapter{} 341 _, err = kubePlugin.getReportContent(context.TODO()) 342 assert.NoError(t, err) 343 }