image_manager_test.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /*
  2. Copyright 2015 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package images
  14. import (
  15. "errors"
  16. "testing"
  17. "time"
  18. "github.com/stretchr/testify/assert"
  19. "k8s.io/api/core/v1"
  20. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  21. "k8s.io/apimachinery/pkg/util/clock"
  22. "k8s.io/client-go/tools/record"
  23. "k8s.io/client-go/util/flowcontrol"
  24. . "k8s.io/kubernetes/pkg/kubelet/container"
  25. ctest "k8s.io/kubernetes/pkg/kubelet/container/testing"
  26. )
  27. type pullerExpects struct {
  28. calls []string
  29. err error
  30. }
  31. type pullerTestCase struct {
  32. containerImage string
  33. policy v1.PullPolicy
  34. inspectErr error
  35. pullerErr error
  36. expected []pullerExpects
  37. }
  38. func pullerTestCases() []pullerTestCase {
  39. return []pullerTestCase{
  40. { // pull missing image
  41. containerImage: "missing_image",
  42. policy: v1.PullIfNotPresent,
  43. inspectErr: nil,
  44. pullerErr: nil,
  45. expected: []pullerExpects{
  46. {[]string{"GetImageRef", "PullImage"}, nil},
  47. }},
  48. { // image present, don't pull
  49. containerImage: "present_image",
  50. policy: v1.PullIfNotPresent,
  51. inspectErr: nil,
  52. pullerErr: nil,
  53. expected: []pullerExpects{
  54. {[]string{"GetImageRef"}, nil},
  55. {[]string{"GetImageRef"}, nil},
  56. {[]string{"GetImageRef"}, nil},
  57. }},
  58. // image present, pull it
  59. {containerImage: "present_image",
  60. policy: v1.PullAlways,
  61. inspectErr: nil,
  62. pullerErr: nil,
  63. expected: []pullerExpects{
  64. {[]string{"GetImageRef", "PullImage"}, nil},
  65. {[]string{"GetImageRef", "PullImage"}, nil},
  66. {[]string{"GetImageRef", "PullImage"}, nil},
  67. }},
  68. // missing image, error PullNever
  69. {containerImage: "missing_image",
  70. policy: v1.PullNever,
  71. inspectErr: nil,
  72. pullerErr: nil,
  73. expected: []pullerExpects{
  74. {[]string{"GetImageRef"}, ErrImageNeverPull},
  75. {[]string{"GetImageRef"}, ErrImageNeverPull},
  76. {[]string{"GetImageRef"}, ErrImageNeverPull},
  77. }},
  78. // missing image, unable to inspect
  79. {containerImage: "missing_image",
  80. policy: v1.PullIfNotPresent,
  81. inspectErr: errors.New("unknown inspectError"),
  82. pullerErr: nil,
  83. expected: []pullerExpects{
  84. {[]string{"GetImageRef"}, ErrImageInspect},
  85. {[]string{"GetImageRef"}, ErrImageInspect},
  86. {[]string{"GetImageRef"}, ErrImageInspect},
  87. }},
  88. // missing image, unable to fetch
  89. {containerImage: "typo_image",
  90. policy: v1.PullIfNotPresent,
  91. inspectErr: nil,
  92. pullerErr: errors.New("404"),
  93. expected: []pullerExpects{
  94. {[]string{"GetImageRef", "PullImage"}, ErrImagePull},
  95. {[]string{"GetImageRef", "PullImage"}, ErrImagePull},
  96. {[]string{"GetImageRef"}, ErrImagePullBackOff},
  97. {[]string{"GetImageRef", "PullImage"}, ErrImagePull},
  98. {[]string{"GetImageRef"}, ErrImagePullBackOff},
  99. {[]string{"GetImageRef"}, ErrImagePullBackOff},
  100. }},
  101. }
  102. }
  103. func pullerTestEnv(c pullerTestCase, serialized bool) (puller ImageManager, fakeClock *clock.FakeClock, fakeRuntime *ctest.FakeRuntime, container *v1.Container) {
  104. container = &v1.Container{
  105. Name: "container_name",
  106. Image: c.containerImage,
  107. ImagePullPolicy: c.policy,
  108. }
  109. backOff := flowcontrol.NewBackOff(time.Second, time.Minute)
  110. fakeClock = clock.NewFakeClock(time.Now())
  111. backOff.Clock = fakeClock
  112. fakeRuntime = &ctest.FakeRuntime{}
  113. fakeRecorder := &record.FakeRecorder{}
  114. fakeRuntime.ImageList = []Image{{ID: "present_image:latest"}}
  115. fakeRuntime.Err = c.pullerErr
  116. fakeRuntime.InspectErr = c.inspectErr
  117. puller = NewImageManager(fakeRecorder, fakeRuntime, backOff, serialized, 0, 0)
  118. return
  119. }
  120. func TestParallelPuller(t *testing.T) {
  121. pod := &v1.Pod{
  122. ObjectMeta: metav1.ObjectMeta{
  123. Name: "test_pod",
  124. Namespace: "test-ns",
  125. UID: "bar",
  126. ResourceVersion: "42",
  127. SelfLink: "/api/v1/pods/foo",
  128. }}
  129. cases := pullerTestCases()
  130. useSerializedEnv := false
  131. for i, c := range cases {
  132. puller, fakeClock, fakeRuntime, container := pullerTestEnv(c, useSerializedEnv)
  133. for tick, expected := range c.expected {
  134. fakeRuntime.CalledFunctions = nil
  135. fakeClock.Step(time.Second)
  136. _, _, err := puller.EnsureImageExists(pod, container, nil, nil)
  137. assert.NoError(t, fakeRuntime.AssertCalls(expected.calls), "in test %d tick=%d", i, tick)
  138. assert.Equal(t, expected.err, err, "in test %d tick=%d", i, tick)
  139. }
  140. }
  141. }
  142. func TestSerializedPuller(t *testing.T) {
  143. pod := &v1.Pod{
  144. ObjectMeta: metav1.ObjectMeta{
  145. Name: "test_pod",
  146. Namespace: "test-ns",
  147. UID: "bar",
  148. ResourceVersion: "42",
  149. SelfLink: "/api/v1/pods/foo",
  150. }}
  151. cases := pullerTestCases()
  152. useSerializedEnv := true
  153. for i, c := range cases {
  154. puller, fakeClock, fakeRuntime, container := pullerTestEnv(c, useSerializedEnv)
  155. for tick, expected := range c.expected {
  156. fakeRuntime.CalledFunctions = nil
  157. fakeClock.Step(time.Second)
  158. _, _, err := puller.EnsureImageExists(pod, container, nil, nil)
  159. assert.NoError(t, fakeRuntime.AssertCalls(expected.calls), "in test %d tick=%d", i, tick)
  160. assert.Equal(t, expected.err, err, "in test %d tick=%d", i, tick)
  161. }
  162. }
  163. }
  164. func TestApplyDefaultImageTag(t *testing.T) {
  165. for _, testCase := range []struct {
  166. Input string
  167. Output string
  168. }{
  169. {Input: "root", Output: "root:latest"},
  170. {Input: "root:tag", Output: "root:tag"},
  171. {Input: "root@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", Output: "root@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},
  172. } {
  173. image, err := applyDefaultImageTag(testCase.Input)
  174. if err != nil {
  175. t.Errorf("applyDefaultImageTag(%s) failed: %v", testCase.Input, err)
  176. } else if image != testCase.Output {
  177. t.Errorf("Expected image reference: %q, got %q", testCase.Output, image)
  178. }
  179. }
  180. }