...

Source file src/k8s.io/kubernetes/pkg/kubelet/kuberuntime/kuberuntime_image_test.go

Documentation: k8s.io/kubernetes/pkg/kubelet/kuberuntime

     1  /*
     2  Copyright 2016 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 kuberuntime
    18  
    19  import (
    20  	"context"
    21  	"encoding/json"
    22  	"fmt"
    23  	"testing"
    24  
    25  	"github.com/stretchr/testify/assert"
    26  	"github.com/stretchr/testify/require"
    27  
    28  	v1 "k8s.io/api/core/v1"
    29  	"k8s.io/apimachinery/pkg/util/sets"
    30  	runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
    31  	"k8s.io/kubernetes/pkg/credentialprovider"
    32  	kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
    33  )
    34  
    35  func TestPullImage(t *testing.T) {
    36  	ctx := context.Background()
    37  	_, _, fakeManager, err := createTestRuntimeManager()
    38  	assert.NoError(t, err)
    39  
    40  	imageRef, err := fakeManager.PullImage(ctx, kubecontainer.ImageSpec{Image: "busybox"}, nil, nil)
    41  	assert.NoError(t, err)
    42  	assert.Equal(t, "busybox", imageRef)
    43  
    44  	images, err := fakeManager.ListImages(ctx)
    45  	assert.NoError(t, err)
    46  	assert.Equal(t, 1, len(images))
    47  	assert.Equal(t, images[0].RepoTags, []string{"busybox"})
    48  }
    49  
    50  func TestPullImageWithError(t *testing.T) {
    51  	ctx := context.Background()
    52  	_, fakeImageService, fakeManager, err := createTestRuntimeManager()
    53  	assert.NoError(t, err)
    54  
    55  	// trying to pull an image with an invalid name should return an error
    56  	imageRef, err := fakeManager.PullImage(ctx, kubecontainer.ImageSpec{Image: ":invalid"}, nil, nil)
    57  	assert.Error(t, err)
    58  	assert.Equal(t, "", imageRef)
    59  
    60  	fakeImageService.InjectError("PullImage", fmt.Errorf("test-error"))
    61  	imageRef, err = fakeManager.PullImage(ctx, kubecontainer.ImageSpec{Image: "busybox"}, nil, nil)
    62  	assert.Error(t, err)
    63  	assert.Equal(t, "", imageRef)
    64  
    65  	images, err := fakeManager.ListImages(ctx)
    66  	assert.NoError(t, err)
    67  	assert.Equal(t, 0, len(images))
    68  }
    69  
    70  func TestPullImageWithInvalidImageName(t *testing.T) {
    71  	_, fakeImageService, fakeManager, err := createTestRuntimeManager()
    72  	assert.NoError(t, err)
    73  
    74  	imageList := []string{"FAIL", "http://fail", "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"}
    75  	fakeImageService.SetFakeImages(imageList)
    76  	for _, val := range imageList {
    77  		ctx := context.Background()
    78  		imageRef, err := fakeManager.PullImage(ctx, kubecontainer.ImageSpec{Image: val}, nil, nil)
    79  		assert.Error(t, err)
    80  		assert.Equal(t, "", imageRef)
    81  
    82  	}
    83  }
    84  
    85  func TestListImages(t *testing.T) {
    86  	ctx := context.Background()
    87  	_, fakeImageService, fakeManager, err := createTestRuntimeManager()
    88  	assert.NoError(t, err)
    89  
    90  	images := []string{"1111", "2222", "3333"}
    91  	expected := sets.NewString(images...)
    92  	fakeImageService.SetFakeImages(images)
    93  
    94  	actualImages, err := fakeManager.ListImages(ctx)
    95  	assert.NoError(t, err)
    96  	actual := sets.NewString()
    97  	for _, i := range actualImages {
    98  		actual.Insert(i.ID)
    99  	}
   100  
   101  	assert.Equal(t, expected.List(), actual.List())
   102  }
   103  
   104  func TestListImagesPinnedField(t *testing.T) {
   105  	ctx := context.Background()
   106  	_, fakeImageService, fakeManager, err := createTestRuntimeManager()
   107  	assert.NoError(t, err)
   108  
   109  	imagesPinned := map[string]bool{
   110  		"1111": false,
   111  		"2222": true,
   112  		"3333": false,
   113  	}
   114  	imageList := []string{}
   115  	for image, pinned := range imagesPinned {
   116  		fakeImageService.SetFakeImagePinned(image, pinned)
   117  		imageList = append(imageList, image)
   118  	}
   119  	fakeImageService.SetFakeImages(imageList)
   120  
   121  	actualImages, err := fakeManager.ListImages(ctx)
   122  	assert.NoError(t, err)
   123  	for _, image := range actualImages {
   124  		assert.Equal(t, imagesPinned[image.ID], image.Pinned)
   125  	}
   126  }
   127  
   128  func TestListImagesWithError(t *testing.T) {
   129  	ctx := context.Background()
   130  	_, fakeImageService, fakeManager, err := createTestRuntimeManager()
   131  	assert.NoError(t, err)
   132  
   133  	fakeImageService.InjectError("ListImages", fmt.Errorf("test-failure"))
   134  
   135  	actualImages, err := fakeManager.ListImages(ctx)
   136  	assert.Error(t, err)
   137  	assert.Nil(t, actualImages)
   138  }
   139  
   140  func TestGetImageRef(t *testing.T) {
   141  	ctx := context.Background()
   142  	_, fakeImageService, fakeManager, err := createTestRuntimeManager()
   143  	assert.NoError(t, err)
   144  
   145  	image := "busybox"
   146  	fakeImageService.SetFakeImages([]string{image})
   147  	imageRef, err := fakeManager.GetImageRef(ctx, kubecontainer.ImageSpec{Image: image})
   148  	assert.NoError(t, err)
   149  	assert.Equal(t, image, imageRef)
   150  }
   151  
   152  func TestImageSize(t *testing.T) {
   153  	ctx := context.Background()
   154  	_, fakeImageService, fakeManager, err := createTestRuntimeManager()
   155  	assert.NoError(t, err)
   156  
   157  	const imageSize = uint64(64)
   158  	fakeImageService.SetFakeImageSize(imageSize)
   159  	image := "busybox"
   160  	fakeImageService.SetFakeImages([]string{image})
   161  	actualSize, err := fakeManager.GetImageSize(ctx, kubecontainer.ImageSpec{Image: image})
   162  	assert.NoError(t, err)
   163  	assert.Equal(t, imageSize, actualSize)
   164  }
   165  
   166  func TestGetImageRefImageNotAvailableLocally(t *testing.T) {
   167  	ctx := context.Background()
   168  	_, _, fakeManager, err := createTestRuntimeManager()
   169  	assert.NoError(t, err)
   170  
   171  	image := "busybox"
   172  
   173  	imageRef, err := fakeManager.GetImageRef(ctx, kubecontainer.ImageSpec{Image: image})
   174  	assert.NoError(t, err)
   175  
   176  	imageNotAvailableLocallyRef := ""
   177  	assert.Equal(t, imageNotAvailableLocallyRef, imageRef)
   178  }
   179  
   180  func TestGetImageRefWithError(t *testing.T) {
   181  	ctx := context.Background()
   182  	_, fakeImageService, fakeManager, err := createTestRuntimeManager()
   183  	assert.NoError(t, err)
   184  
   185  	image := "busybox"
   186  
   187  	fakeImageService.InjectError("ImageStatus", fmt.Errorf("test-error"))
   188  
   189  	imageRef, err := fakeManager.GetImageRef(ctx, kubecontainer.ImageSpec{Image: image})
   190  	assert.Error(t, err)
   191  	assert.Equal(t, "", imageRef)
   192  }
   193  
   194  func TestRemoveImage(t *testing.T) {
   195  	ctx := context.Background()
   196  	_, fakeImageService, fakeManager, err := createTestRuntimeManager()
   197  	assert.NoError(t, err)
   198  
   199  	_, err = fakeManager.PullImage(ctx, kubecontainer.ImageSpec{Image: "busybox"}, nil, nil)
   200  	assert.NoError(t, err)
   201  	assert.Equal(t, 1, len(fakeImageService.Images))
   202  
   203  	err = fakeManager.RemoveImage(ctx, kubecontainer.ImageSpec{Image: "busybox"})
   204  	assert.NoError(t, err)
   205  	assert.Equal(t, 0, len(fakeImageService.Images))
   206  }
   207  
   208  func TestRemoveImageNoOpIfImageNotLocal(t *testing.T) {
   209  	ctx := context.Background()
   210  	_, _, fakeManager, err := createTestRuntimeManager()
   211  	assert.NoError(t, err)
   212  
   213  	err = fakeManager.RemoveImage(ctx, kubecontainer.ImageSpec{Image: "busybox"})
   214  	assert.NoError(t, err)
   215  }
   216  
   217  func TestRemoveImageWithError(t *testing.T) {
   218  	ctx := context.Background()
   219  	_, fakeImageService, fakeManager, err := createTestRuntimeManager()
   220  	assert.NoError(t, err)
   221  
   222  	_, err = fakeManager.PullImage(ctx, kubecontainer.ImageSpec{Image: "busybox"}, nil, nil)
   223  	assert.NoError(t, err)
   224  	assert.Equal(t, 1, len(fakeImageService.Images))
   225  
   226  	fakeImageService.InjectError("RemoveImage", fmt.Errorf("test-failure"))
   227  
   228  	err = fakeManager.RemoveImage(ctx, kubecontainer.ImageSpec{Image: "busybox"})
   229  	assert.Error(t, err)
   230  	assert.Equal(t, 1, len(fakeImageService.Images))
   231  }
   232  
   233  func TestImageStats(t *testing.T) {
   234  	ctx := context.Background()
   235  	_, fakeImageService, fakeManager, err := createTestRuntimeManager()
   236  	assert.NoError(t, err)
   237  
   238  	const imageSize = 64
   239  	fakeImageService.SetFakeImageSize(imageSize)
   240  	images := []string{"1111", "2222", "3333"}
   241  	fakeImageService.SetFakeImages(images)
   242  
   243  	actualStats, err := fakeManager.ImageStats(ctx)
   244  	assert.NoError(t, err)
   245  	expectedStats := &kubecontainer.ImageStats{TotalStorageBytes: imageSize * uint64(len(images))}
   246  	assert.Equal(t, expectedStats, actualStats)
   247  }
   248  
   249  func TestImageStatsWithError(t *testing.T) {
   250  	ctx := context.Background()
   251  	_, fakeImageService, fakeManager, err := createTestRuntimeManager()
   252  	assert.NoError(t, err)
   253  
   254  	fakeImageService.InjectError("ListImages", fmt.Errorf("test-failure"))
   255  
   256  	actualImageStats, err := fakeManager.ImageStats(ctx)
   257  	assert.Error(t, err)
   258  	assert.Nil(t, actualImageStats)
   259  }
   260  
   261  func TestPullWithSecrets(t *testing.T) {
   262  	ctx := context.Background()
   263  	// auth value is equivalent to: "username":"passed-user","password":"passed-password"
   264  	dockerCfg := map[string]map[string]string{"index.docker.io/v1/": {"email": "passed-email", "auth": "cGFzc2VkLXVzZXI6cGFzc2VkLXBhc3N3b3Jk"}}
   265  	dockercfgContent, err := json.Marshal(dockerCfg)
   266  	if err != nil {
   267  		t.Errorf("unexpected error: %v", err)
   268  	}
   269  
   270  	dockerConfigJSON := map[string]map[string]map[string]string{"auths": dockerCfg}
   271  	dockerConfigJSONContent, err := json.Marshal(dockerConfigJSON)
   272  	if err != nil {
   273  		t.Errorf("unexpected error: %v", err)
   274  	}
   275  
   276  	tests := map[string]struct {
   277  		imageName           string
   278  		passedSecrets       []v1.Secret
   279  		builtInDockerConfig credentialprovider.DockerConfig
   280  		expectedAuth        *runtimeapi.AuthConfig
   281  	}{
   282  		"no matching secrets": {
   283  			"ubuntu",
   284  			[]v1.Secret{},
   285  			credentialprovider.DockerConfig(map[string]credentialprovider.DockerConfigEntry{}),
   286  			nil,
   287  		},
   288  		"default keyring secrets": {
   289  			"ubuntu",
   290  			[]v1.Secret{},
   291  			credentialprovider.DockerConfig(map[string]credentialprovider.DockerConfigEntry{
   292  				"index.docker.io/v1/": {Username: "built-in", Password: "password", Provider: nil},
   293  			}),
   294  			&runtimeapi.AuthConfig{Username: "built-in", Password: "password"},
   295  		},
   296  		"default keyring secrets unused": {
   297  			"ubuntu",
   298  			[]v1.Secret{},
   299  			credentialprovider.DockerConfig(map[string]credentialprovider.DockerConfigEntry{
   300  				"extraneous": {Username: "built-in", Password: "password", Provider: nil},
   301  			}),
   302  			nil,
   303  		},
   304  		"builtin keyring secrets, but use passed": {
   305  			"ubuntu",
   306  			[]v1.Secret{{Type: v1.SecretTypeDockercfg, Data: map[string][]byte{v1.DockerConfigKey: dockercfgContent}}},
   307  			credentialprovider.DockerConfig(map[string]credentialprovider.DockerConfigEntry{
   308  				"index.docker.io/v1/": {Username: "built-in", Password: "password", Provider: nil},
   309  			}),
   310  			&runtimeapi.AuthConfig{Username: "passed-user", Password: "passed-password"},
   311  		},
   312  		"builtin keyring secrets, but use passed with new docker config": {
   313  			"ubuntu",
   314  			[]v1.Secret{{Type: v1.SecretTypeDockerConfigJson, Data: map[string][]byte{v1.DockerConfigJsonKey: dockerConfigJSONContent}}},
   315  			credentialprovider.DockerConfig(map[string]credentialprovider.DockerConfigEntry{
   316  				"index.docker.io/v1/": {Username: "built-in", Password: "password", Provider: nil},
   317  			}),
   318  			&runtimeapi.AuthConfig{Username: "passed-user", Password: "passed-password"},
   319  		},
   320  	}
   321  	for description, test := range tests {
   322  		builtInKeyRing := &credentialprovider.BasicDockerKeyring{}
   323  		builtInKeyRing.Add(test.builtInDockerConfig)
   324  		_, fakeImageService, fakeManager, err := customTestRuntimeManager(builtInKeyRing)
   325  		require.NoError(t, err)
   326  
   327  		_, err = fakeManager.PullImage(ctx, kubecontainer.ImageSpec{Image: test.imageName}, test.passedSecrets, nil)
   328  		require.NoError(t, err)
   329  		fakeImageService.AssertImagePulledWithAuth(t, &runtimeapi.ImageSpec{Image: test.imageName, Annotations: make(map[string]string)}, test.expectedAuth, description)
   330  	}
   331  }
   332  
   333  func TestPullWithSecretsWithError(t *testing.T) {
   334  	ctx := context.Background()
   335  
   336  	dockerCfg := map[string]map[string]map[string]string{
   337  		"auths": {
   338  			"index.docker.io/v1/": {
   339  				"email": "passed-email",
   340  				"auth":  "cGFzc2VkLXVzZXI6cGFzc2VkLXBhc3N3b3Jk",
   341  			},
   342  		},
   343  	}
   344  
   345  	dockerConfigJSON, err := json.Marshal(dockerCfg)
   346  	if err != nil {
   347  		t.Fatal(err)
   348  	}
   349  
   350  	for _, test := range []struct {
   351  		name              string
   352  		imageName         string
   353  		passedSecrets     []v1.Secret
   354  		shouldInjectError bool
   355  	}{
   356  		{
   357  			name:          "invalid docker secret",
   358  			imageName:     "ubuntu",
   359  			passedSecrets: []v1.Secret{{Type: v1.SecretTypeDockercfg, Data: map[string][]byte{v1.DockerConfigKey: []byte("invalid")}}},
   360  		},
   361  		{
   362  			name:      "secret provided, pull failed",
   363  			imageName: "ubuntu",
   364  			passedSecrets: []v1.Secret{
   365  				{Type: v1.SecretTypeDockerConfigJson, Data: map[string][]byte{v1.DockerConfigKey: dockerConfigJSON}},
   366  			},
   367  			shouldInjectError: true,
   368  		},
   369  	} {
   370  		t.Run(test.name, func(t *testing.T) {
   371  			_, fakeImageService, fakeManager, err := createTestRuntimeManager()
   372  			assert.NoError(t, err)
   373  
   374  			if test.shouldInjectError {
   375  				fakeImageService.InjectError("PullImage", fmt.Errorf("test-error"))
   376  			}
   377  
   378  			imageRef, err := fakeManager.PullImage(ctx, kubecontainer.ImageSpec{Image: test.imageName}, test.passedSecrets, nil)
   379  			assert.Error(t, err)
   380  			assert.Equal(t, "", imageRef)
   381  
   382  			images, err := fakeManager.ListImages(ctx)
   383  			assert.NoError(t, err)
   384  			assert.Equal(t, 0, len(images))
   385  		})
   386  	}
   387  }
   388  
   389  func TestPullThenListWithAnnotations(t *testing.T) {
   390  	ctx := context.Background()
   391  	_, _, fakeManager, err := createTestRuntimeManager()
   392  	assert.NoError(t, err)
   393  
   394  	imageSpec := kubecontainer.ImageSpec{
   395  		Image: "12345",
   396  		Annotations: []kubecontainer.Annotation{
   397  			{Name: "kubernetes.io/runtimehandler", Value: "handler_name"},
   398  		},
   399  	}
   400  
   401  	_, err = fakeManager.PullImage(ctx, imageSpec, nil, nil)
   402  	assert.NoError(t, err)
   403  
   404  	images, err := fakeManager.ListImages(ctx)
   405  	assert.NoError(t, err)
   406  	assert.Equal(t, 1, len(images))
   407  	assert.Equal(t, images[0].Spec, imageSpec)
   408  }
   409  

View as plain text