k8s.io/kubernetes@v1.29.3/pkg/kubelet/cm/dra/state/state_checkpoint_test.go (about)

     1  /*
     2  Copyright 2020 The Kubernetes 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 state
    18  
    19  import (
    20  	"os"
    21  	"path"
    22  	"strings"
    23  	"testing"
    24  
    25  	"github.com/stretchr/testify/assert"
    26  
    27  	resourcev1alpha2 "k8s.io/api/resource/v1alpha2"
    28  	"k8s.io/apimachinery/pkg/util/sets"
    29  	"k8s.io/kubernetes/pkg/kubelet/checkpointmanager"
    30  	testutil "k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/state/testing"
    31  )
    32  
    33  const testingCheckpoint = "dramanager_checkpoint_test"
    34  
    35  // assertStateEqual marks provided test as failed if provided states differ
    36  func assertStateEqual(t *testing.T, restoredState, expectedState ClaimInfoStateList) {
    37  	assert.Equal(t, expectedState, restoredState, "expected ClaimInfoState does not equal to restored one")
    38  }
    39  
    40  func TestCheckpointGetOrCreate(t *testing.T) {
    41  	testCases := []struct {
    42  		description       string
    43  		checkpointContent string
    44  		expectedError     string
    45  		expectedState     ClaimInfoStateList
    46  	}{
    47  		{
    48  			"Create non-existing checkpoint",
    49  			"",
    50  			"",
    51  			[]ClaimInfoState{},
    52  		},
    53  		{
    54  			"Restore checkpoint - single claim",
    55  			`{"version":"v1","entries":[{"DriverName":"test-driver.cdi.k8s.io","ClassName":"class-name","ClaimUID":"067798be-454e-4be4-9047-1aa06aea63f7","ClaimName":"example","Namespace":"default","PodUIDs":{"139cdb46-f989-4f17-9561-ca10cfb509a6":{}},"ResourceHandles":[{"driverName":"test-driver.cdi.k8s.io","data":"{\"a\": \"b\"}"}],"CDIDevices":{"test-driver.cdi.k8s.io":["example.com/example=cdi-example"]}}],"checksum":4194867564}`,
    56  			"",
    57  			[]ClaimInfoState{
    58  				{
    59  					DriverName: "test-driver.cdi.k8s.io",
    60  					ClassName:  "class-name",
    61  					ClaimUID:   "067798be-454e-4be4-9047-1aa06aea63f7",
    62  					ClaimName:  "example",
    63  					Namespace:  "default",
    64  					PodUIDs:    sets.New("139cdb46-f989-4f17-9561-ca10cfb509a6"),
    65  					ResourceHandles: []resourcev1alpha2.ResourceHandle{
    66  						{
    67  							DriverName: "test-driver.cdi.k8s.io",
    68  							Data:       `{"a": "b"}`,
    69  						},
    70  					},
    71  					CDIDevices: map[string][]string{
    72  						"test-driver.cdi.k8s.io": {"example.com/example=cdi-example"},
    73  					},
    74  				},
    75  			},
    76  		},
    77  		{
    78  			"Restore checkpoint - single claim - multiple devices",
    79  			`{"version":"v1","entries":[{"DriverName":"meta-test-driver.cdi.k8s.io","ClassName":"class-name","ClaimUID":"067798be-454e-4be4-9047-1aa06aea63f7","ClaimName":"example","Namespace":"default","PodUIDs":{"139cdb46-f989-4f17-9561-ca10cfb509a6":{}},"ResourceHandles":[{"driverName":"test-driver-1.cdi.k8s.io","data":"{\"a\": \"b\"}"},{"driverName":"test-driver-2.cdi.k8s.io","data":"{\"c\": \"d\"}"}],"CDIDevices":{"test-driver-1.cdi.k8s.io":["example-1.com/example-1=cdi-example-1"],"test-driver-2.cdi.k8s.io":["example-2.com/example-2=cdi-example-2"]}}],"checksum":360176657}`,
    80  			"",
    81  			[]ClaimInfoState{
    82  				{
    83  					DriverName: "meta-test-driver.cdi.k8s.io",
    84  					ClassName:  "class-name",
    85  					ClaimUID:   "067798be-454e-4be4-9047-1aa06aea63f7",
    86  					ClaimName:  "example",
    87  					Namespace:  "default",
    88  					PodUIDs:    sets.New("139cdb46-f989-4f17-9561-ca10cfb509a6"),
    89  					ResourceHandles: []resourcev1alpha2.ResourceHandle{
    90  						{
    91  							DriverName: "test-driver-1.cdi.k8s.io",
    92  							Data:       `{"a": "b"}`,
    93  						},
    94  						{
    95  							DriverName: "test-driver-2.cdi.k8s.io",
    96  							Data:       `{"c": "d"}`,
    97  						},
    98  					},
    99  					CDIDevices: map[string][]string{
   100  						"test-driver-1.cdi.k8s.io": {"example-1.com/example-1=cdi-example-1"},
   101  						"test-driver-2.cdi.k8s.io": {"example-2.com/example-2=cdi-example-2"},
   102  					},
   103  				},
   104  			},
   105  		},
   106  		{
   107  			"Restore checkpoint - multiple claims",
   108  			`{"version":"v1","entries":[{"DriverName":"test-driver.cdi.k8s.io","ClassName":"class-name-1","ClaimUID":"067798be-454e-4be4-9047-1aa06aea63f7","ClaimName":"example-1","Namespace":"default","PodUIDs":{"139cdb46-f989-4f17-9561-ca10cfb509a6":{}},"ResourceHandles":[{"driverName":"test-driver.cdi.k8s.io","data":"{\"a\": \"b\"}"}],"CDIDevices":{"test-driver.cdi.k8s.io":["example.com/example=cdi-example-1"]}},{"DriverName":"test-driver.cdi.k8s.io","ClassName":"class-name-2","ClaimUID":"4cf8db2d-06c0-7d70-1a51-e59b25b2c16c","ClaimName":"example-2","Namespace":"default","PodUIDs":{"139cdb46-f989-4f17-9561-ca10cfb509a6":{}},"ResourceHandles":[{"driverName":"test-driver.cdi.k8s.io","data":"{\"c\": \"d\"}"}],"CDIDevices":{"test-driver.cdi.k8s.io":["example.com/example=cdi-example-2"]}}],"checksum":103176902}`,
   109  			"",
   110  			[]ClaimInfoState{
   111  				{
   112  					DriverName: "test-driver.cdi.k8s.io",
   113  					ClassName:  "class-name-1",
   114  					ClaimUID:   "067798be-454e-4be4-9047-1aa06aea63f7",
   115  					ClaimName:  "example-1",
   116  					Namespace:  "default",
   117  					PodUIDs:    sets.New("139cdb46-f989-4f17-9561-ca10cfb509a6"),
   118  					ResourceHandles: []resourcev1alpha2.ResourceHandle{
   119  						{
   120  							DriverName: "test-driver.cdi.k8s.io",
   121  							Data:       `{"a": "b"}`,
   122  						},
   123  					},
   124  					CDIDevices: map[string][]string{
   125  						"test-driver.cdi.k8s.io": {"example.com/example=cdi-example-1"},
   126  					},
   127  				},
   128  				{
   129  					DriverName: "test-driver.cdi.k8s.io",
   130  					ClassName:  "class-name-2",
   131  					ClaimUID:   "4cf8db2d-06c0-7d70-1a51-e59b25b2c16c",
   132  					ClaimName:  "example-2",
   133  					Namespace:  "default",
   134  					PodUIDs:    sets.New("139cdb46-f989-4f17-9561-ca10cfb509a6"),
   135  					ResourceHandles: []resourcev1alpha2.ResourceHandle{
   136  						{
   137  							DriverName: "test-driver.cdi.k8s.io",
   138  							Data:       `{"c": "d"}`,
   139  						},
   140  					},
   141  					CDIDevices: map[string][]string{
   142  						"test-driver.cdi.k8s.io": {"example.com/example=cdi-example-2"},
   143  					},
   144  				},
   145  			},
   146  		},
   147  		{
   148  			"Restore checkpoint - invalid checksum",
   149  			`{"version":"v1","entries":[{"DriverName":"test-driver.cdi.k8s.io","ClassName":"class-name","ClaimUID":"067798be-454e-4be4-9047-1aa06aea63f7","ClaimName":"example","Namespace":"default","PodUIDs":{"139cdb46-f989-4f17-9561-ca10cfb509a6":{}},"CDIDevices":{"test-driver.cdi.k8s.io":["example.com/example=cdi-example"]}}],"checksum":1988120168}`,
   150  			"checkpoint is corrupted",
   151  			[]ClaimInfoState{},
   152  		},
   153  		{
   154  			"Restore checkpoint with invalid JSON",
   155  			`{`,
   156  			"unexpected end of JSON input",
   157  			[]ClaimInfoState{},
   158  		},
   159  	}
   160  
   161  	// create temp dir
   162  	testingDir, err := os.MkdirTemp("", "dramanager_state_test")
   163  	if err != nil {
   164  		t.Fatal(err)
   165  	}
   166  	defer os.RemoveAll(testingDir)
   167  
   168  	// create checkpoint manager for testing
   169  	cpm, err := checkpointmanager.NewCheckpointManager(testingDir)
   170  	assert.NoError(t, err, "could not create testing checkpoint manager")
   171  
   172  	for _, tc := range testCases {
   173  		t.Run(tc.description, func(t *testing.T) {
   174  			// ensure there is no previous checkpoint
   175  			assert.NoError(t, cpm.RemoveCheckpoint(testingCheckpoint), "could not remove testing checkpoint")
   176  
   177  			// prepare checkpoint for testing
   178  			if strings.TrimSpace(tc.checkpointContent) != "" {
   179  				checkpoint := &testutil.MockCheckpoint{Content: tc.checkpointContent}
   180  				assert.NoError(t, cpm.CreateCheckpoint(testingCheckpoint, checkpoint), "could not create testing checkpoint")
   181  			}
   182  
   183  			var state ClaimInfoStateList
   184  
   185  			checkpointState, err := NewCheckpointState(testingDir, testingCheckpoint)
   186  
   187  			if err == nil {
   188  				state, err = checkpointState.GetOrCreate()
   189  			}
   190  			if strings.TrimSpace(tc.expectedError) != "" {
   191  				assert.Error(t, err)
   192  				assert.Contains(t, err.Error(), tc.expectedError)
   193  			} else {
   194  				assert.NoError(t, err, "unexpected error while creating checkpointState")
   195  				// compare state after restoration with the one expected
   196  				assertStateEqual(t, state, tc.expectedState)
   197  			}
   198  		})
   199  	}
   200  }
   201  
   202  func TestCheckpointStateStore(t *testing.T) {
   203  	claimInfoState := ClaimInfoState{
   204  		DriverName: "test-driver.cdi.k8s.io",
   205  		ClassName:  "class-name",
   206  		ClaimUID:   "067798be-454e-4be4-9047-1aa06aea63f7",
   207  		ClaimName:  "example",
   208  		Namespace:  "default",
   209  		PodUIDs:    sets.New("139cdb46-f989-4f17-9561-ca10cfb509a6"),
   210  		ResourceHandles: []resourcev1alpha2.ResourceHandle{
   211  			{
   212  				DriverName: "test-driver.cdi.k8s.io",
   213  				Data:       `{"a": "b"}`,
   214  			},
   215  		},
   216  		CDIDevices: map[string][]string{
   217  			"test-driver.cdi.k8s.io": {"example.com/example=cdi-example"},
   218  		},
   219  	}
   220  
   221  	expectedCheckpoint := `{"version":"v1","entries":[{"DriverName":"test-driver.cdi.k8s.io","ClassName":"class-name","ClaimUID":"067798be-454e-4be4-9047-1aa06aea63f7","ClaimName":"example","Namespace":"default","PodUIDs":{"139cdb46-f989-4f17-9561-ca10cfb509a6":{}},"ResourceHandles":[{"driverName":"test-driver.cdi.k8s.io","data":"{\"a\": \"b\"}"}],"CDIDevices":{"test-driver.cdi.k8s.io":["example.com/example=cdi-example"]}}],"checksum":4194867564}`
   222  
   223  	// Should return an error, stateDir cannot be an empty string
   224  	if _, err := NewCheckpointState("", testingCheckpoint); err == nil {
   225  		t.Fatal("expected error but got nil")
   226  	}
   227  
   228  	// create temp dir
   229  	testingDir, err := os.MkdirTemp("", "dramanager_state_test")
   230  	if err != nil {
   231  		t.Fatal(err)
   232  	}
   233  	defer os.RemoveAll(testingDir)
   234  
   235  	cpm, err := checkpointmanager.NewCheckpointManager(testingDir)
   236  	assert.NoError(t, err, "could not create testing checkpoint manager")
   237  	assert.NoError(t, cpm.RemoveCheckpoint(testingCheckpoint), "could not remove testing checkpoint")
   238  
   239  	cs, err := NewCheckpointState(testingDir, testingCheckpoint)
   240  	assert.NoError(t, err, "could not create testing checkpointState instance")
   241  	err = cs.Store(ClaimInfoStateList{claimInfoState})
   242  	assert.NoError(t, err, "could not store ClaimInfoState")
   243  	checkpoint := NewDRAManagerCheckpoint()
   244  	cpm.GetCheckpoint(testingCheckpoint, checkpoint)
   245  	checkpointData, err := checkpoint.MarshalCheckpoint()
   246  	assert.NoError(t, err, "could not Marshal Checkpoint")
   247  	assert.Equal(t, expectedCheckpoint, string(checkpointData), "expected ClaimInfoState does not equal to restored one")
   248  
   249  	// NewCheckpointState with an empty checkpointName should return an error
   250  	if _, err = NewCheckpointState(testingDir, ""); err == nil {
   251  		t.Fatal("expected error but got nil")
   252  	}
   253  }
   254  
   255  func TestOldCheckpointRestore(t *testing.T) {
   256  	testingDir := t.TempDir()
   257  	cpm, err := checkpointmanager.NewCheckpointManager(testingDir)
   258  	assert.NoError(t, err, "could not create testing checkpoint manager")
   259  
   260  	oldCheckpointData := `{"version":"v1","entries":[{"DriverName":"test-driver.cdi.k8s.io","ClassName":"class-name","ClaimUID":"067798be-454e-4be4-9047-1aa06aea63f7","ClaimName":"example","Namespace":"default","PodUIDs":{"139cdb46-f989-4f17-9561-ca10cfb509a6":{}},"CDIDevices":{"test-driver.cdi.k8s.io":["example.com/example=cdi-example"]}}],"checksum":153446146}`
   261  	err = os.WriteFile(path.Join(testingDir, testingCheckpoint), []byte(oldCheckpointData), 0644)
   262  	assert.NoError(t, err, "could not store checkpoint data")
   263  
   264  	checkpoint := NewDRAManagerCheckpoint()
   265  	err = cpm.GetCheckpoint(testingCheckpoint, checkpoint)
   266  	assert.NoError(t, err, "could not restore checkpoint")
   267  
   268  	checkpointData, err := checkpoint.MarshalCheckpoint()
   269  	assert.NoError(t, err, "could not Marshal Checkpoint")
   270  
   271  	expectedData := `{"version":"v1","entries":[{"DriverName":"test-driver.cdi.k8s.io","ClassName":"class-name","ClaimUID":"067798be-454e-4be4-9047-1aa06aea63f7","ClaimName":"example","Namespace":"default","PodUIDs":{"139cdb46-f989-4f17-9561-ca10cfb509a6":{}},"ResourceHandles":null,"CDIDevices":{"test-driver.cdi.k8s.io":["example.com/example=cdi-example"]}}],"checksum":453625682}`
   272  	assert.Equal(t, expectedData, string(checkpointData), "expected ClaimInfoState does not equal to restored one")
   273  }