github.com/kubewharf/katalyst-core@v0.5.3/pkg/controller/spd/cnc_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 spd
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/stretchr/testify/assert"
    25  	appsv1 "k8s.io/api/apps/v1"
    26  	v1 "k8s.io/api/core/v1"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	"k8s.io/apimachinery/pkg/runtime"
    29  	"k8s.io/client-go/tools/cache"
    30  	"k8s.io/utils/pointer"
    31  
    32  	apis "github.com/kubewharf/katalyst-api/pkg/apis/autoscaling/v1alpha1"
    33  	configapi "github.com/kubewharf/katalyst-api/pkg/apis/config/v1alpha1"
    34  	apiworkload "github.com/kubewharf/katalyst-api/pkg/apis/workload/v1alpha1"
    35  	"github.com/kubewharf/katalyst-api/pkg/consts"
    36  	katalystbase "github.com/kubewharf/katalyst-core/cmd/base"
    37  	"github.com/kubewharf/katalyst-core/pkg/config/controller"
    38  	"github.com/kubewharf/katalyst-core/pkg/config/generic"
    39  )
    40  
    41  func Test_cncCacheController_Run(t *testing.T) {
    42  	t.Parallel()
    43  
    44  	type fields struct {
    45  		pod            *v1.Pod
    46  		workload       *appsv1.StatefulSet
    47  		spd            *apiworkload.ServiceProfileDescriptor
    48  		cnc            *configapi.CustomNodeConfig
    49  		enableCNCCache bool
    50  	}
    51  	tests := []struct {
    52  		name    string
    53  		fields  fields
    54  		wantCNC *configapi.CustomNodeConfig
    55  	}{
    56  		{
    57  			name: "update cnc spd config when cnc cache enable",
    58  			fields: fields{
    59  				pod: &v1.Pod{
    60  					ObjectMeta: metav1.ObjectMeta{
    61  						Name:      "pod1",
    62  						Namespace: "default",
    63  						OwnerReferences: []metav1.OwnerReference{
    64  							{
    65  								APIVersion: "apps/v1",
    66  								Kind:       "StatefulSet",
    67  								Name:       "sts1",
    68  							},
    69  						},
    70  						Annotations: map[string]string{
    71  							consts.PodAnnotationSPDNameKey: "spd1",
    72  						},
    73  						Labels: map[string]string{
    74  							"workload": "sts1",
    75  						},
    76  					},
    77  					Spec: v1.PodSpec{
    78  						NodeName: "node1",
    79  					},
    80  				},
    81  				workload: &appsv1.StatefulSet{
    82  					TypeMeta: metav1.TypeMeta{
    83  						Kind:       "StatefulSet",
    84  						APIVersion: "apps/v1",
    85  					},
    86  					ObjectMeta: metav1.ObjectMeta{
    87  						Name:      "sts1",
    88  						Namespace: "default",
    89  						Annotations: map[string]string{
    90  							consts.WorkloadAnnotationSPDEnableKey: consts.WorkloadAnnotationSPDEnabled,
    91  						},
    92  					},
    93  					Spec: appsv1.StatefulSetSpec{
    94  						Selector: &metav1.LabelSelector{
    95  							MatchLabels: map[string]string{
    96  								"workload": "sts1",
    97  							},
    98  						},
    99  						Template: v1.PodTemplateSpec{
   100  							ObjectMeta: metav1.ObjectMeta{
   101  								Annotations: map[string]string{
   102  									"katalyst.kubewharf.io/qos_level": "dedicated_cores",
   103  								},
   104  							},
   105  							Spec: v1.PodSpec{},
   106  						},
   107  					},
   108  				},
   109  				spd: &apiworkload.ServiceProfileDescriptor{
   110  					ObjectMeta: metav1.ObjectMeta{
   111  						Namespace: "default",
   112  						Name:      "sts1",
   113  						OwnerReferences: []metav1.OwnerReference{
   114  							{
   115  								APIVersion: "apps/v1",
   116  								Kind:       "StatefulSet",
   117  								Name:       "sts1",
   118  							},
   119  						},
   120  					},
   121  					Spec: apiworkload.ServiceProfileDescriptorSpec{
   122  						TargetRef: apis.CrossVersionObjectReference{
   123  							Kind:       stsGVK.Kind,
   124  							Name:       "sts1",
   125  							APIVersion: stsGVK.GroupVersion().String(),
   126  						},
   127  						BaselinePercent: pointer.Int32(100),
   128  					},
   129  					Status: apiworkload.ServiceProfileDescriptorStatus{
   130  						AggMetrics: []apiworkload.AggPodMetrics{},
   131  					},
   132  				},
   133  				cnc: &configapi.CustomNodeConfig{
   134  					ObjectMeta: metav1.ObjectMeta{
   135  						Name: "node1",
   136  					},
   137  				},
   138  				enableCNCCache: true,
   139  			},
   140  			wantCNC: &configapi.CustomNodeConfig{
   141  				ObjectMeta: metav1.ObjectMeta{
   142  					Name: "node1",
   143  				},
   144  				Status: configapi.CustomNodeConfigStatus{
   145  					ServiceProfileConfigList: []configapi.TargetConfig{
   146  						{
   147  							ConfigNamespace: "default",
   148  							ConfigName:      "sts1",
   149  							Hash:            "51131be1b092",
   150  						},
   151  					},
   152  				},
   153  			},
   154  		},
   155  		{
   156  			name: "clear cnc spd config when cnc cache disable",
   157  			fields: fields{
   158  				pod: &v1.Pod{
   159  					ObjectMeta: metav1.ObjectMeta{
   160  						Name:      "pod1",
   161  						Namespace: "default",
   162  						OwnerReferences: []metav1.OwnerReference{
   163  							{
   164  								APIVersion: "apps/v1",
   165  								Kind:       "StatefulSet",
   166  								Name:       "sts1",
   167  							},
   168  						},
   169  						Annotations: map[string]string{
   170  							consts.PodAnnotationSPDNameKey: "spd1",
   171  						},
   172  						Labels: map[string]string{
   173  							"workload": "sts1",
   174  						},
   175  					},
   176  					Spec: v1.PodSpec{
   177  						NodeName: "node1",
   178  					},
   179  				},
   180  				workload: &appsv1.StatefulSet{
   181  					TypeMeta: metav1.TypeMeta{
   182  						Kind:       "StatefulSet",
   183  						APIVersion: "apps/v1",
   184  					},
   185  					ObjectMeta: metav1.ObjectMeta{
   186  						Name:      "sts1",
   187  						Namespace: "default",
   188  						Annotations: map[string]string{
   189  							consts.WorkloadAnnotationSPDEnableKey: consts.WorkloadAnnotationSPDEnabled,
   190  						},
   191  					},
   192  					Spec: appsv1.StatefulSetSpec{
   193  						Selector: &metav1.LabelSelector{
   194  							MatchLabels: map[string]string{
   195  								"workload": "sts1",
   196  							},
   197  						},
   198  						Template: v1.PodTemplateSpec{
   199  							ObjectMeta: metav1.ObjectMeta{
   200  								Annotations: map[string]string{
   201  									"katalyst.kubewharf.io/qos_level": "dedicated_cores",
   202  								},
   203  							},
   204  							Spec: v1.PodSpec{},
   205  						},
   206  					},
   207  				},
   208  				spd: &apiworkload.ServiceProfileDescriptor{
   209  					ObjectMeta: metav1.ObjectMeta{
   210  						Namespace: "default",
   211  						Name:      "sts1",
   212  						OwnerReferences: []metav1.OwnerReference{
   213  							{
   214  								APIVersion: "apps/v1",
   215  								Kind:       "StatefulSet",
   216  								Name:       "sts1",
   217  							},
   218  						},
   219  					},
   220  					Spec: apiworkload.ServiceProfileDescriptorSpec{
   221  						TargetRef: apis.CrossVersionObjectReference{
   222  							Kind:       stsGVK.Kind,
   223  							Name:       "sts1",
   224  							APIVersion: stsGVK.GroupVersion().String(),
   225  						},
   226  						BaselinePercent: pointer.Int32(100),
   227  					},
   228  					Status: apiworkload.ServiceProfileDescriptorStatus{
   229  						AggMetrics: []apiworkload.AggPodMetrics{},
   230  					},
   231  				},
   232  				cnc: &configapi.CustomNodeConfig{
   233  					ObjectMeta: metav1.ObjectMeta{
   234  						Name: "node1",
   235  					},
   236  					Status: configapi.CustomNodeConfigStatus{
   237  						ServiceProfileConfigList: []configapi.TargetConfig{
   238  							{
   239  								ConfigNamespace: "default",
   240  								ConfigName:      "sts1",
   241  								Hash:            "51131be1b092",
   242  							},
   243  						},
   244  					},
   245  				},
   246  				enableCNCCache: false,
   247  			},
   248  			wantCNC: &configapi.CustomNodeConfig{
   249  				ObjectMeta: metav1.ObjectMeta{
   250  					Name: "node1",
   251  				},
   252  				Status: configapi.CustomNodeConfigStatus{},
   253  			},
   254  		},
   255  	}
   256  	for _, tt := range tests {
   257  		tt := tt
   258  		t.Run(tt.name, func(t *testing.T) {
   259  			t.Parallel()
   260  
   261  			spdConfig := &controller.SPDConfig{
   262  				EnableCNCCache:         tt.fields.enableCNCCache,
   263  				SPDWorkloadGVResources: []string{"statefulsets.v1.apps"},
   264  			}
   265  			genericConfig := &generic.GenericConfiguration{}
   266  			controllerConf := &controller.GenericControllerConfiguration{
   267  				DynamicGVResources: []string{"statefulsets.v1.apps"},
   268  			}
   269  
   270  			ctx := context.TODO()
   271  			controlCtx, err := katalystbase.GenerateFakeGenericContext([]runtime.Object{tt.fields.pod},
   272  				[]runtime.Object{tt.fields.spd, tt.fields.cnc}, []runtime.Object{tt.fields.workload})
   273  			assert.NoError(t, err)
   274  
   275  			spdController, err := NewSPDController(ctx, controlCtx, genericConfig, controllerConf,
   276  				spdConfig, generic.NewQoSConfiguration(), struct{}{})
   277  			assert.NoError(t, err)
   278  
   279  			controlCtx.StartInformer(ctx)
   280  			go spdController.Run()
   281  			synced := cache.WaitForCacheSync(ctx.Done(), spdController.syncedFunc...)
   282  			assert.True(t, synced)
   283  			time.Sleep(1 * time.Second)
   284  
   285  			newCNC, err := controlCtx.Client.InternalClient.ConfigV1alpha1().CustomNodeConfigs().
   286  				Get(ctx, tt.fields.cnc.Name, metav1.GetOptions{})
   287  			assert.NoError(t, err)
   288  			assert.Equal(t, tt.wantCNC, newCNC)
   289  		})
   290  	}
   291  }