k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/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 // TODO (https://github.com/kubernetes/kubernetes/issues/123552): reconsider what data gets stored in checkpoints and whether that is really necessary. 41 // 42 // As it stands now, a "v1" checkpoint contains data for types like the resourcev1alpha2.ResourceHandle 43 // which may change over time as new fields get added in a backward-compatible way (not unusual 44 // for API types). That breaks checksuming with pkg/util/hash because it is based on spew output. 45 // That output includes those new fields. 46 47 func TestCheckpointGetOrCreate(t *testing.T) { 48 testCases := []struct { 49 description string 50 checkpointContent string 51 expectedError string 52 expectedState ClaimInfoStateList 53 }{ 54 { 55 "Create non-existing checkpoint", 56 "", 57 "", 58 []ClaimInfoState{}, 59 }, 60 { 61 "Restore checkpoint - single claim", 62 `{"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":113577689}`, 63 "", 64 []ClaimInfoState{ 65 { 66 DriverName: "test-driver.cdi.k8s.io", 67 ClassName: "class-name", 68 ClaimUID: "067798be-454e-4be4-9047-1aa06aea63f7", 69 ClaimName: "example", 70 Namespace: "default", 71 PodUIDs: sets.New("139cdb46-f989-4f17-9561-ca10cfb509a6"), 72 ResourceHandles: []resourcev1alpha2.ResourceHandle{ 73 { 74 DriverName: "test-driver.cdi.k8s.io", 75 Data: `{"a": "b"}`, 76 }, 77 }, 78 CDIDevices: map[string][]string{ 79 "test-driver.cdi.k8s.io": {"example.com/example=cdi-example"}, 80 }, 81 }, 82 }, 83 }, 84 { 85 "Restore checkpoint - single claim - multiple devices", 86 `{"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":1466990255}`, 87 "", 88 []ClaimInfoState{ 89 { 90 DriverName: "meta-test-driver.cdi.k8s.io", 91 ClassName: "class-name", 92 ClaimUID: "067798be-454e-4be4-9047-1aa06aea63f7", 93 ClaimName: "example", 94 Namespace: "default", 95 PodUIDs: sets.New("139cdb46-f989-4f17-9561-ca10cfb509a6"), 96 ResourceHandles: []resourcev1alpha2.ResourceHandle{ 97 { 98 DriverName: "test-driver-1.cdi.k8s.io", 99 Data: `{"a": "b"}`, 100 }, 101 { 102 DriverName: "test-driver-2.cdi.k8s.io", 103 Data: `{"c": "d"}`, 104 }, 105 }, 106 CDIDevices: map[string][]string{ 107 "test-driver-1.cdi.k8s.io": {"example-1.com/example-1=cdi-example-1"}, 108 "test-driver-2.cdi.k8s.io": {"example-2.com/example-2=cdi-example-2"}, 109 }, 110 }, 111 }, 112 }, 113 { 114 "Restore checkpoint - multiple claims", 115 `{"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":471181742}`, 116 "", 117 []ClaimInfoState{ 118 { 119 DriverName: "test-driver.cdi.k8s.io", 120 ClassName: "class-name-1", 121 ClaimUID: "067798be-454e-4be4-9047-1aa06aea63f7", 122 ClaimName: "example-1", 123 Namespace: "default", 124 PodUIDs: sets.New("139cdb46-f989-4f17-9561-ca10cfb509a6"), 125 ResourceHandles: []resourcev1alpha2.ResourceHandle{ 126 { 127 DriverName: "test-driver.cdi.k8s.io", 128 Data: `{"a": "b"}`, 129 }, 130 }, 131 CDIDevices: map[string][]string{ 132 "test-driver.cdi.k8s.io": {"example.com/example=cdi-example-1"}, 133 }, 134 }, 135 { 136 DriverName: "test-driver.cdi.k8s.io", 137 ClassName: "class-name-2", 138 ClaimUID: "4cf8db2d-06c0-7d70-1a51-e59b25b2c16c", 139 ClaimName: "example-2", 140 Namespace: "default", 141 PodUIDs: sets.New("139cdb46-f989-4f17-9561-ca10cfb509a6"), 142 ResourceHandles: []resourcev1alpha2.ResourceHandle{ 143 { 144 DriverName: "test-driver.cdi.k8s.io", 145 Data: `{"c": "d"}`, 146 }, 147 }, 148 CDIDevices: map[string][]string{ 149 "test-driver.cdi.k8s.io": {"example.com/example=cdi-example-2"}, 150 }, 151 }, 152 }, 153 }, 154 { 155 "Restore checkpoint - invalid checksum", 156 `{"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}`, 157 "checkpoint is corrupted", 158 []ClaimInfoState{}, 159 }, 160 { 161 "Restore checkpoint with invalid JSON", 162 `{`, 163 "unexpected end of JSON input", 164 []ClaimInfoState{}, 165 }, 166 } 167 168 // create temp dir 169 testingDir, err := os.MkdirTemp("", "dramanager_state_test") 170 if err != nil { 171 t.Fatal(err) 172 } 173 defer os.RemoveAll(testingDir) 174 175 // create checkpoint manager for testing 176 cpm, err := checkpointmanager.NewCheckpointManager(testingDir) 177 assert.NoError(t, err, "could not create testing checkpoint manager") 178 179 for _, tc := range testCases { 180 t.Run(tc.description, func(t *testing.T) { 181 // ensure there is no previous checkpoint 182 assert.NoError(t, cpm.RemoveCheckpoint(testingCheckpoint), "could not remove testing checkpoint") 183 184 // prepare checkpoint for testing 185 if strings.TrimSpace(tc.checkpointContent) != "" { 186 checkpoint := &testutil.MockCheckpoint{Content: tc.checkpointContent} 187 assert.NoError(t, cpm.CreateCheckpoint(testingCheckpoint, checkpoint), "could not create testing checkpoint") 188 } 189 190 var state ClaimInfoStateList 191 192 checkpointState, err := NewCheckpointState(testingDir, testingCheckpoint) 193 194 if err == nil { 195 state, err = checkpointState.GetOrCreate() 196 } 197 if strings.TrimSpace(tc.expectedError) != "" { 198 assert.Error(t, err) 199 assert.Contains(t, err.Error(), tc.expectedError) 200 } else { 201 assert.NoError(t, err, "unexpected error while creating checkpointState") 202 // compare state after restoration with the one expected 203 assertStateEqual(t, state, tc.expectedState) 204 } 205 }) 206 } 207 } 208 209 func TestCheckpointStateStore(t *testing.T) { 210 claimInfoState := ClaimInfoState{ 211 DriverName: "test-driver.cdi.k8s.io", 212 ClassName: "class-name", 213 ClaimUID: "067798be-454e-4be4-9047-1aa06aea63f7", 214 ClaimName: "example", 215 Namespace: "default", 216 PodUIDs: sets.New("139cdb46-f989-4f17-9561-ca10cfb509a6"), 217 ResourceHandles: []resourcev1alpha2.ResourceHandle{ 218 { 219 DriverName: "test-driver.cdi.k8s.io", 220 Data: `{"a": "b"}`, 221 }, 222 }, 223 CDIDevices: map[string][]string{ 224 "test-driver.cdi.k8s.io": {"example.com/example=cdi-example"}, 225 }, 226 } 227 228 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":113577689}` 229 230 // Should return an error, stateDir cannot be an empty string 231 if _, err := NewCheckpointState("", testingCheckpoint); err == nil { 232 t.Fatal("expected error but got nil") 233 } 234 235 // create temp dir 236 testingDir, err := os.MkdirTemp("", "dramanager_state_test") 237 if err != nil { 238 t.Fatal(err) 239 } 240 defer os.RemoveAll(testingDir) 241 242 cpm, err := checkpointmanager.NewCheckpointManager(testingDir) 243 assert.NoError(t, err, "could not create testing checkpoint manager") 244 assert.NoError(t, cpm.RemoveCheckpoint(testingCheckpoint), "could not remove testing checkpoint") 245 246 cs, err := NewCheckpointState(testingDir, testingCheckpoint) 247 assert.NoError(t, err, "could not create testing checkpointState instance") 248 err = cs.Store(ClaimInfoStateList{claimInfoState}) 249 assert.NoError(t, err, "could not store ClaimInfoState") 250 checkpoint := NewDRAManagerCheckpoint() 251 cpm.GetCheckpoint(testingCheckpoint, checkpoint) 252 checkpointData, err := checkpoint.MarshalCheckpoint() 253 assert.NoError(t, err, "could not Marshal Checkpoint") 254 assert.Equal(t, expectedCheckpoint, string(checkpointData), "expected ClaimInfoState does not equal to restored one") 255 256 // NewCheckpointState with an empty checkpointName should return an error 257 if _, err = NewCheckpointState(testingDir, ""); err == nil { 258 t.Fatal("expected error but got nil") 259 } 260 } 261 262 func TestOldCheckpointRestore(t *testing.T) { 263 testingDir := t.TempDir() 264 cpm, err := checkpointmanager.NewCheckpointManager(testingDir) 265 assert.NoError(t, err, "could not create testing checkpoint manager") 266 267 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}` 268 err = os.WriteFile(path.Join(testingDir, testingCheckpoint), []byte(oldCheckpointData), 0644) 269 assert.NoError(t, err, "could not store checkpoint data") 270 271 checkpoint := NewDRAManagerCheckpoint() 272 err = cpm.GetCheckpoint(testingCheckpoint, checkpoint) 273 assert.NoError(t, err, "could not restore checkpoint") 274 275 checkpointData, err := checkpoint.MarshalCheckpoint() 276 assert.NoError(t, err, "could not Marshal Checkpoint") 277 278 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}` 279 assert.Equal(t, expectedData, string(checkpointData), "expected ClaimInfoState does not equal to restored one") 280 }