...

Source file src/k8s.io/kubernetes/pkg/kubelet/cm/dra/state/state_checkpoint_test.go

Documentation: k8s.io/kubernetes/pkg/kubelet/cm/dra/state

     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  }
   281  

View as plain text