sync_test.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. /*
  2. Copyright 2017 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 sync
  14. import (
  15. "context"
  16. "fmt"
  17. "net"
  18. "reflect"
  19. "testing"
  20. "time"
  21. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  22. "k8s.io/klog"
  23. "k8s.io/kubernetes/pkg/controller/nodeipam/ipam/cidrset"
  24. "k8s.io/kubernetes/pkg/controller/nodeipam/ipam/test"
  25. "k8s.io/api/core/v1"
  26. )
  27. var (
  28. _, clusterCIDRRange, _ = net.ParseCIDR("10.1.0.0/16")
  29. )
  30. type fakeEvent struct {
  31. nodeName string
  32. reason string
  33. }
  34. type fakeAPIs struct {
  35. aliasRange *net.IPNet
  36. aliasErr error
  37. addAliasErr error
  38. nodeRet *v1.Node
  39. nodeErr error
  40. updateNodeErr error
  41. resyncTimeout time.Duration
  42. reportChan chan struct{}
  43. updateNodeNetworkUnavailableErr error
  44. calls []string
  45. events []fakeEvent
  46. results []error
  47. }
  48. func (f *fakeAPIs) Alias(ctx context.Context, nodeName string) (*net.IPNet, error) {
  49. f.calls = append(f.calls, fmt.Sprintf("alias %v", nodeName))
  50. return f.aliasRange, f.aliasErr
  51. }
  52. func (f *fakeAPIs) AddAlias(ctx context.Context, nodeName string, cidrRange *net.IPNet) error {
  53. f.calls = append(f.calls, fmt.Sprintf("addAlias %v %v", nodeName, cidrRange))
  54. return f.addAliasErr
  55. }
  56. func (f *fakeAPIs) Node(ctx context.Context, name string) (*v1.Node, error) {
  57. f.calls = append(f.calls, fmt.Sprintf("node %v", name))
  58. return f.nodeRet, f.nodeErr
  59. }
  60. func (f *fakeAPIs) UpdateNodePodCIDR(ctx context.Context, node *v1.Node, cidrRange *net.IPNet) error {
  61. f.calls = append(f.calls, fmt.Sprintf("updateNode %v", node))
  62. return f.updateNodeErr
  63. }
  64. func (f *fakeAPIs) UpdateNodeNetworkUnavailable(nodeName string, unavailable bool) error {
  65. f.calls = append(f.calls, fmt.Sprintf("updateNodeNetworkUnavailable %v %v", nodeName, unavailable))
  66. return f.updateNodeNetworkUnavailableErr
  67. }
  68. func (f *fakeAPIs) EmitNodeWarningEvent(nodeName, reason, fmtStr string, args ...interface{}) {
  69. f.events = append(f.events, fakeEvent{nodeName, reason})
  70. }
  71. func (f *fakeAPIs) ReportResult(err error) {
  72. klog.V(2).Infof("ReportResult %v", err)
  73. f.results = append(f.results, err)
  74. if f.reportChan != nil {
  75. f.reportChan <- struct{}{}
  76. }
  77. }
  78. func (f *fakeAPIs) ResyncTimeout() time.Duration {
  79. if f.resyncTimeout == 0 {
  80. return time.Second * 10000
  81. }
  82. return f.resyncTimeout
  83. }
  84. func (f *fakeAPIs) dumpTrace() {
  85. for i, x := range f.calls {
  86. klog.Infof("trace %v: %v", i, x)
  87. }
  88. }
  89. var nodeWithoutCIDRRange = &v1.Node{
  90. ObjectMeta: metav1.ObjectMeta{Name: "node1"},
  91. }
  92. var nodeWithCIDRRange = &v1.Node{
  93. ObjectMeta: metav1.ObjectMeta{Name: "node1"},
  94. Spec: v1.NodeSpec{PodCIDR: "10.1.1.0/24"},
  95. }
  96. func TestNodeSyncUpdate(t *testing.T) {
  97. t.Parallel()
  98. for _, tc := range []struct {
  99. desc string
  100. mode NodeSyncMode
  101. node *v1.Node
  102. fake fakeAPIs
  103. events []fakeEvent
  104. wantError bool
  105. }{
  106. {
  107. desc: "validate range ==",
  108. mode: SyncFromCloud,
  109. node: nodeWithCIDRRange,
  110. fake: fakeAPIs{
  111. aliasRange: test.MustParseCIDR(nodeWithCIDRRange.Spec.PodCIDR),
  112. },
  113. },
  114. {
  115. desc: "validate range !=",
  116. mode: SyncFromCloud,
  117. node: nodeWithCIDRRange,
  118. fake: fakeAPIs{aliasRange: test.MustParseCIDR("192.168.0.0/24")},
  119. events: []fakeEvent{{"node1", "CloudCIDRAllocatorMismatch"}},
  120. },
  121. {
  122. desc: "update alias from node",
  123. mode: SyncFromCloud,
  124. node: nodeWithCIDRRange,
  125. events: []fakeEvent{{"node1", "CloudCIDRAllocatorInvalidMode"}},
  126. wantError: true,
  127. },
  128. {
  129. desc: "update alias from node",
  130. mode: SyncFromCluster,
  131. node: nodeWithCIDRRange,
  132. // XXX/bowei -- validation
  133. },
  134. {
  135. desc: "update node from alias",
  136. mode: SyncFromCloud,
  137. node: nodeWithoutCIDRRange,
  138. fake: fakeAPIs{aliasRange: test.MustParseCIDR("10.1.2.3/16")},
  139. // XXX/bowei -- validation
  140. },
  141. {
  142. desc: "update node from alias",
  143. mode: SyncFromCluster,
  144. node: nodeWithoutCIDRRange,
  145. fake: fakeAPIs{aliasRange: test.MustParseCIDR("10.1.2.3/16")},
  146. events: []fakeEvent{{"node1", "CloudCIDRAllocatorInvalidMode"}},
  147. wantError: true,
  148. },
  149. {
  150. desc: "allocate range",
  151. mode: SyncFromCloud,
  152. node: nodeWithoutCIDRRange,
  153. events: []fakeEvent{{"node1", "CloudCIDRAllocatorInvalidMode"}},
  154. wantError: true,
  155. },
  156. {
  157. desc: "allocate range",
  158. mode: SyncFromCluster,
  159. node: nodeWithoutCIDRRange,
  160. },
  161. {
  162. desc: "update with node==nil",
  163. mode: SyncFromCluster,
  164. node: nil,
  165. fake: fakeAPIs{
  166. nodeRet: nodeWithCIDRRange,
  167. },
  168. wantError: false,
  169. },
  170. } {
  171. cidr, _ := cidrset.NewCIDRSet(clusterCIDRRange, 24)
  172. sync := New(&tc.fake, &tc.fake, &tc.fake, tc.mode, "node1", cidr)
  173. doneChan := make(chan struct{})
  174. // Do a single step of the loop.
  175. go sync.Loop(doneChan)
  176. sync.Update(tc.node)
  177. close(sync.opChan)
  178. <-doneChan
  179. tc.fake.dumpTrace()
  180. if !reflect.DeepEqual(tc.fake.events, tc.events) {
  181. t.Errorf("%v, %v; fake.events = %#v, want %#v", tc.desc, tc.mode, tc.fake.events, tc.events)
  182. }
  183. var hasError bool
  184. for _, r := range tc.fake.results {
  185. hasError = hasError || (r != nil)
  186. }
  187. if hasError != tc.wantError {
  188. t.Errorf("%v, %v; hasError = %t, errors = %v, want %t",
  189. tc.desc, tc.mode, hasError, tc.fake.events, tc.wantError)
  190. }
  191. }
  192. }
  193. func TestNodeSyncResync(t *testing.T) {
  194. fake := &fakeAPIs{
  195. nodeRet: nodeWithCIDRRange,
  196. resyncTimeout: time.Millisecond,
  197. reportChan: make(chan struct{}),
  198. }
  199. cidr, _ := cidrset.NewCIDRSet(clusterCIDRRange, 24)
  200. sync := New(fake, fake, fake, SyncFromCluster, "node1", cidr)
  201. doneChan := make(chan struct{})
  202. go sync.Loop(doneChan)
  203. <-fake.reportChan
  204. close(sync.opChan)
  205. // Unblock loop().
  206. go func() {
  207. <-fake.reportChan
  208. }()
  209. <-doneChan
  210. fake.dumpTrace()
  211. }
  212. func TestNodeSyncDelete(t *testing.T) {
  213. t.Parallel()
  214. for _, tc := range []struct {
  215. desc string
  216. mode NodeSyncMode
  217. node *v1.Node
  218. fake fakeAPIs
  219. }{
  220. {
  221. desc: "delete",
  222. mode: SyncFromCluster,
  223. node: nodeWithCIDRRange,
  224. },
  225. {
  226. desc: "delete without CIDR range",
  227. mode: SyncFromCluster,
  228. node: nodeWithoutCIDRRange,
  229. },
  230. {
  231. desc: "delete with invalid CIDR range",
  232. mode: SyncFromCluster,
  233. node: &v1.Node{
  234. ObjectMeta: metav1.ObjectMeta{Name: "node1"},
  235. Spec: v1.NodeSpec{PodCIDR: "invalid"},
  236. },
  237. },
  238. } {
  239. cidr, _ := cidrset.NewCIDRSet(clusterCIDRRange, 24)
  240. sync := New(&tc.fake, &tc.fake, &tc.fake, tc.mode, "node1", cidr)
  241. doneChan := make(chan struct{})
  242. // Do a single step of the loop.
  243. go sync.Loop(doneChan)
  244. sync.Delete(tc.node)
  245. <-doneChan
  246. tc.fake.dumpTrace()
  247. /*
  248. if !reflect.DeepEqual(tc.fake.events, tc.events) {
  249. t.Errorf("%v, %v; fake.events = %#v, want %#v", tc.desc, tc.mode, tc.fake.events, tc.events)
  250. }
  251. var hasError bool
  252. for _, r := range tc.fake.results {
  253. hasError = hasError || (r != nil)
  254. }
  255. if hasError != tc.wantError {
  256. t.Errorf("%v, %v; hasError = %t, errors = %v, want %t",
  257. tc.desc, tc.mode, hasError, tc.fake.events, tc.wantError)
  258. }
  259. */
  260. }
  261. }