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 }