kubenet_linux_test.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  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 kubenet
  14. import (
  15. "fmt"
  16. "github.com/stretchr/testify/assert"
  17. "github.com/stretchr/testify/mock"
  18. "testing"
  19. kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
  20. kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
  21. "k8s.io/kubernetes/pkg/kubelet/dockershim/network"
  22. "k8s.io/kubernetes/pkg/kubelet/dockershim/network/cni/testing"
  23. hostporttest "k8s.io/kubernetes/pkg/kubelet/dockershim/network/hostport/testing"
  24. nettest "k8s.io/kubernetes/pkg/kubelet/dockershim/network/testing"
  25. "k8s.io/kubernetes/pkg/util/bandwidth"
  26. ipttest "k8s.io/kubernetes/pkg/util/iptables/testing"
  27. sysctltest "k8s.io/kubernetes/pkg/util/sysctl/testing"
  28. "k8s.io/utils/exec"
  29. fakeexec "k8s.io/utils/exec/testing"
  30. )
  31. // test it fulfills the NetworkPlugin interface
  32. var _ network.NetworkPlugin = &kubenetNetworkPlugin{}
  33. func newFakeKubenetPlugin(initMap map[kubecontainer.ContainerID]string, execer exec.Interface, host network.Host) *kubenetNetworkPlugin {
  34. return &kubenetNetworkPlugin{
  35. podIPs: initMap,
  36. execer: execer,
  37. mtu: 1460,
  38. host: host,
  39. }
  40. }
  41. func TestGetPodNetworkStatus(t *testing.T) {
  42. podIPMap := make(map[kubecontainer.ContainerID]string)
  43. podIPMap[kubecontainer.ContainerID{ID: "1"}] = "10.245.0.2"
  44. podIPMap[kubecontainer.ContainerID{ID: "2"}] = "10.245.0.3"
  45. testCases := []struct {
  46. id string
  47. expectError bool
  48. expectIP string
  49. }{
  50. //in podCIDR map
  51. {
  52. "1",
  53. false,
  54. "10.245.0.2",
  55. },
  56. {
  57. "2",
  58. false,
  59. "10.245.0.3",
  60. },
  61. //not in podCIDR map
  62. {
  63. "3",
  64. true,
  65. "",
  66. },
  67. //TODO: add test cases for retrieving ip inside container network namespace
  68. }
  69. fakeCmds := make([]fakeexec.FakeCommandAction, 0)
  70. for _, t := range testCases {
  71. // the fake commands return the IP from the given index, or an error
  72. fCmd := fakeexec.FakeCmd{
  73. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  74. func() ([]byte, error) {
  75. ip, ok := podIPMap[kubecontainer.ContainerID{ID: t.id}]
  76. if !ok {
  77. return nil, fmt.Errorf("Pod IP %q not found", t.id)
  78. }
  79. return []byte(ip), nil
  80. },
  81. },
  82. }
  83. fakeCmds = append(fakeCmds, func(cmd string, args ...string) exec.Cmd {
  84. return fakeexec.InitFakeCmd(&fCmd, cmd, args...)
  85. })
  86. }
  87. fexec := fakeexec.FakeExec{
  88. CommandScript: fakeCmds,
  89. LookPathFunc: func(file string) (string, error) {
  90. return fmt.Sprintf("/fake-bin/%s", file), nil
  91. },
  92. }
  93. fhost := nettest.NewFakeHost(nil)
  94. fakeKubenet := newFakeKubenetPlugin(podIPMap, &fexec, fhost)
  95. for i, tc := range testCases {
  96. out, err := fakeKubenet.GetPodNetworkStatus("", "", kubecontainer.ContainerID{ID: tc.id})
  97. if tc.expectError {
  98. if err == nil {
  99. t.Errorf("Test case %d expects error but got none", i)
  100. }
  101. continue
  102. } else {
  103. if err != nil {
  104. t.Errorf("Test case %d expects error but got error: %v", i, err)
  105. }
  106. }
  107. if tc.expectIP != out.IP.String() {
  108. t.Errorf("Test case %d expects ip %s but got %s", i, tc.expectIP, out.IP.String())
  109. }
  110. }
  111. }
  112. // TestTeardownCallsShaper tests that a `TearDown` call does call
  113. // `shaper.Reset`
  114. func TestTeardownCallsShaper(t *testing.T) {
  115. fexec := &fakeexec.FakeExec{
  116. CommandScript: []fakeexec.FakeCommandAction{},
  117. LookPathFunc: func(file string) (string, error) {
  118. return fmt.Sprintf("/fake-bin/%s", file), nil
  119. },
  120. }
  121. fhost := nettest.NewFakeHost(nil)
  122. fshaper := &bandwidth.FakeShaper{}
  123. mockcni := &mock_cni.MockCNI{}
  124. kubenet := newFakeKubenetPlugin(map[kubecontainer.ContainerID]string{}, fexec, fhost)
  125. kubenet.cniConfig = mockcni
  126. kubenet.iptables = ipttest.NewFake()
  127. kubenet.bandwidthShaper = fshaper
  128. kubenet.hostportSyncer = hostporttest.NewFakeHostportSyncer()
  129. mockcni.On("DelNetwork", mock.AnythingOfType("*libcni.NetworkConfig"), mock.AnythingOfType("*libcni.RuntimeConf")).Return(nil)
  130. details := make(map[string]interface{})
  131. details[network.NET_PLUGIN_EVENT_POD_CIDR_CHANGE_DETAIL_CIDR] = "10.0.0.1/24"
  132. kubenet.Event(network.NET_PLUGIN_EVENT_POD_CIDR_CHANGE, details)
  133. existingContainerID := kubecontainer.BuildContainerID("docker", "123")
  134. kubenet.podIPs[existingContainerID] = "10.0.0.1"
  135. if err := kubenet.TearDownPod("namespace", "name", existingContainerID); err != nil {
  136. t.Fatalf("Unexpected error in TearDownPod: %v", err)
  137. }
  138. assert.Equal(t, []string{"10.0.0.1/32"}, fshaper.ResetCIDRs, "shaper.Reset should have been called")
  139. mockcni.AssertExpectations(t)
  140. }
  141. // TestInit tests that a `Init` call with an MTU sets the MTU
  142. func TestInit_MTU(t *testing.T) {
  143. var fakeCmds []fakeexec.FakeCommandAction
  144. {
  145. // modprobe br-netfilter
  146. fCmd := fakeexec.FakeCmd{
  147. CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{
  148. func() ([]byte, error) {
  149. return make([]byte, 0), nil
  150. },
  151. },
  152. }
  153. fakeCmds = append(fakeCmds, func(cmd string, args ...string) exec.Cmd {
  154. return fakeexec.InitFakeCmd(&fCmd, cmd, args...)
  155. })
  156. }
  157. fexec := &fakeexec.FakeExec{
  158. CommandScript: fakeCmds,
  159. LookPathFunc: func(file string) (string, error) {
  160. return fmt.Sprintf("/fake-bin/%s", file), nil
  161. },
  162. }
  163. fhost := nettest.NewFakeHost(nil)
  164. kubenet := newFakeKubenetPlugin(map[kubecontainer.ContainerID]string{}, fexec, fhost)
  165. kubenet.iptables = ipttest.NewFake()
  166. sysctl := sysctltest.NewFake()
  167. sysctl.Settings["net/bridge/bridge-nf-call-iptables"] = 0
  168. kubenet.sysctl = sysctl
  169. if err := kubenet.Init(nettest.NewFakeHost(nil), kubeletconfig.HairpinNone, "10.0.0.0/8", 1234); err != nil {
  170. t.Fatalf("Unexpected error in Init: %v", err)
  171. }
  172. assert.Equal(t, 1234, kubenet.mtu, "kubenet.mtu should have been set")
  173. assert.Equal(t, 1, sysctl.Settings["net/bridge/bridge-nf-call-iptables"], "net/bridge/bridge-nf-call-iptables sysctl should have been set")
  174. }
  175. // TestInvocationWithoutRuntime invokes the plugin without a runtime.
  176. // This is how kubenet is invoked from the cri.
  177. func TestTearDownWithoutRuntime(t *testing.T) {
  178. testCases := []struct {
  179. podCIDR string
  180. ip string
  181. expectedGateway string
  182. }{
  183. {
  184. podCIDR: "10.0.0.1/24",
  185. ip: "10.0.0.1",
  186. expectedGateway: "10.0.0.1",
  187. },
  188. {
  189. podCIDR: "2001:beef::1/48",
  190. ip: "2001:beef::1",
  191. expectedGateway: "2001:beef::1",
  192. },
  193. }
  194. for _, tc := range testCases {
  195. fhost := nettest.NewFakeHost(nil)
  196. fhost.Legacy = false
  197. mockcni := &mock_cni.MockCNI{}
  198. fexec := &fakeexec.FakeExec{
  199. CommandScript: []fakeexec.FakeCommandAction{},
  200. LookPathFunc: func(file string) (string, error) {
  201. return fmt.Sprintf("/fake-bin/%s", file), nil
  202. },
  203. }
  204. kubenet := newFakeKubenetPlugin(map[kubecontainer.ContainerID]string{}, fexec, fhost)
  205. kubenet.cniConfig = mockcni
  206. kubenet.iptables = ipttest.NewFake()
  207. details := make(map[string]interface{})
  208. details[network.NET_PLUGIN_EVENT_POD_CIDR_CHANGE_DETAIL_CIDR] = tc.podCIDR
  209. kubenet.Event(network.NET_PLUGIN_EVENT_POD_CIDR_CHANGE, details)
  210. if kubenet.gateway.String() != tc.expectedGateway {
  211. t.Errorf("generated gateway: %q, expecting: %q", kubenet.gateway.String(), tc.expectedGateway)
  212. }
  213. if kubenet.podCidr != tc.podCIDR {
  214. t.Errorf("generated podCidr: %q, expecting: %q", kubenet.podCidr, tc.podCIDR)
  215. }
  216. existingContainerID := kubecontainer.BuildContainerID("docker", "123")
  217. kubenet.podIPs[existingContainerID] = tc.ip
  218. mockcni.On("DelNetwork", mock.AnythingOfType("*libcni.NetworkConfig"), mock.AnythingOfType("*libcni.RuntimeConf")).Return(nil)
  219. if err := kubenet.TearDownPod("namespace", "name", existingContainerID); err != nil {
  220. t.Fatalf("Unexpected error in TearDownPod: %v", err)
  221. }
  222. // Assert that the CNI DelNetwork made it through and we didn't crash
  223. // without a runtime.
  224. mockcni.AssertExpectations(t)
  225. }
  226. }
  227. //TODO: add unit test for each implementation of network plugin interface