subnet_test.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. // Copyright 2015 CoreOS, Inc.
  2. //
  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. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package subnet
  15. import (
  16. "encoding/json"
  17. "fmt"
  18. "reflect"
  19. "testing"
  20. "time"
  21. "github.com/coreos/flannel/Godeps/_workspace/src/github.com/coreos/go-etcd/etcd"
  22. "github.com/coreos/flannel/Godeps/_workspace/src/golang.org/x/net/context"
  23. "github.com/coreos/flannel/pkg/ip"
  24. )
  25. type mockSubnetRegistry struct {
  26. subnets *etcd.Node
  27. addCh chan string
  28. delCh chan string
  29. index uint64
  30. ttl uint64
  31. }
  32. func newMockSubnetRegistry(ttlOverride uint64) *mockSubnetRegistry {
  33. subnodes := []*etcd.Node{
  34. &etcd.Node{Key: "10.3.1.0-24", Value: `{ "PublicIP": "1.1.1.1" }`, ModifiedIndex: 10},
  35. &etcd.Node{Key: "10.3.2.0-24", Value: `{ "PublicIP": "1.1.1.1" }`, ModifiedIndex: 11},
  36. &etcd.Node{Key: "10.3.4.0-24", Value: `{ "PublicIP": "1.1.1.1" }`, ModifiedIndex: 12},
  37. &etcd.Node{Key: "10.3.5.0-24", Value: `{ "PublicIP": "1.1.1.1" }`, ModifiedIndex: 13},
  38. }
  39. return &mockSubnetRegistry{
  40. subnets: &etcd.Node{
  41. Nodes: subnodes,
  42. },
  43. addCh: make(chan string),
  44. delCh: make(chan string),
  45. index: 14,
  46. ttl: ttlOverride,
  47. }
  48. }
  49. func (msr *mockSubnetRegistry) getConfig(ctx context.Context, network string) (*etcd.Response, error) {
  50. return &etcd.Response{
  51. EtcdIndex: msr.index,
  52. Node: &etcd.Node{
  53. Value: `{ "Network": "10.3.0.0/16", "SubnetMin": "10.3.1.0", "SubnetMax": "10.3.5.0" }`,
  54. },
  55. }, nil
  56. }
  57. func (msr *mockSubnetRegistry) getSubnets(ctx context.Context, network string) (*etcd.Response, error) {
  58. return &etcd.Response{
  59. Node: msr.subnets,
  60. EtcdIndex: msr.index,
  61. }, nil
  62. }
  63. func (msr *mockSubnetRegistry) createSubnet(ctx context.Context, network, sn, data string, ttl uint64) (*etcd.Response, error) {
  64. msr.index += 1
  65. if msr.ttl > 0 {
  66. ttl = msr.ttl
  67. }
  68. // add squared durations :)
  69. exp := time.Now().Add(time.Duration(ttl) * time.Second)
  70. node := &etcd.Node{
  71. Key: sn,
  72. Value: data,
  73. ModifiedIndex: msr.index,
  74. Expiration: &exp,
  75. }
  76. msr.subnets.Nodes = append(msr.subnets.Nodes, node)
  77. return &etcd.Response{
  78. Node: node,
  79. EtcdIndex: msr.index,
  80. }, nil
  81. }
  82. func (msr *mockSubnetRegistry) updateSubnet(ctx context.Context, network, sn, data string, ttl uint64) (*etcd.Response, error) {
  83. msr.index += 1
  84. // add squared durations :)
  85. exp := time.Now().Add(time.Duration(ttl) * time.Second)
  86. for _, n := range msr.subnets.Nodes {
  87. if n.Key == sn {
  88. n.Value = data
  89. n.ModifiedIndex = msr.index
  90. n.Expiration = &exp
  91. return &etcd.Response{
  92. Node: n,
  93. EtcdIndex: msr.index,
  94. }, nil
  95. }
  96. }
  97. return nil, fmt.Errorf("Subnet not found")
  98. }
  99. func (msr *mockSubnetRegistry) watchSubnets(ctx context.Context, network string, since uint64) (*etcd.Response, error) {
  100. var sn string
  101. select {
  102. case <-ctx.Done():
  103. return nil, ctx.Err()
  104. case sn = <-msr.addCh:
  105. n := etcd.Node{
  106. Key: sn,
  107. Value: `{"PublicIP": "1.1.1.1"}`,
  108. ModifiedIndex: msr.index,
  109. }
  110. msr.subnets.Nodes = append(msr.subnets.Nodes, &n)
  111. return &etcd.Response{
  112. Action: "add",
  113. Node: &n,
  114. }, nil
  115. case sn = <-msr.delCh:
  116. for i, n := range msr.subnets.Nodes {
  117. if n.Key == sn {
  118. msr.subnets.Nodes[i] = msr.subnets.Nodes[len(msr.subnets.Nodes)-1]
  119. msr.subnets.Nodes = msr.subnets.Nodes[:len(msr.subnets.Nodes)-2]
  120. return &etcd.Response{
  121. Action: "expire",
  122. Node: n,
  123. }, nil
  124. }
  125. }
  126. return nil, fmt.Errorf("Subnet (%s) to delete was not found: ", sn)
  127. }
  128. }
  129. func (msr *mockSubnetRegistry) hasSubnet(sn string) bool {
  130. for _, n := range msr.subnets.Nodes {
  131. if n.Key == sn {
  132. return true
  133. }
  134. }
  135. return false
  136. }
  137. func TestAcquireLease(t *testing.T) {
  138. msr := newMockSubnetRegistry(0)
  139. sm := newEtcdManager(msr)
  140. extIP, _ := ip.ParseIP4("1.2.3.4")
  141. attrs := LeaseAttrs{
  142. PublicIP: extIP,
  143. }
  144. l, err := sm.AcquireLease(context.Background(), "", &attrs)
  145. if err != nil {
  146. t.Fatal("AcquireLease failed: ", err)
  147. }
  148. if l.Subnet.String() != "10.3.3.0/24" {
  149. t.Fatal("Subnet mismatch: expected 10.3.3.0/24, got: ", l.Subnet)
  150. }
  151. // Acquire again, should reuse
  152. if l, err = sm.AcquireLease(context.Background(), "", &attrs); err != nil {
  153. t.Fatal("AcquireLease failed: ", err)
  154. }
  155. if l.Subnet.String() != "10.3.3.0/24" {
  156. t.Fatal("Subnet mismatch: expected 10.3.3.0/24, got: ", l.Subnet)
  157. }
  158. }
  159. func TestWatchLeaseAdded(t *testing.T) {
  160. msr := newMockSubnetRegistry(0)
  161. sm := newEtcdManager(msr)
  162. ctx, cancel := context.WithCancel(context.Background())
  163. defer cancel()
  164. events := make(chan []Event)
  165. go WatchLeases(ctx, sm, "", events)
  166. expected := "10.3.3.0-24"
  167. msr.addCh <- expected
  168. evtBatch, ok := <-events
  169. if !ok {
  170. t.Fatalf("WatchSubnets did not publish")
  171. }
  172. if len(evtBatch) != 1 {
  173. t.Fatalf("WatchSubnets produced wrong sized event batch")
  174. }
  175. evt := evtBatch[0]
  176. if evt.Type != SubnetAdded {
  177. t.Fatalf("WatchSubnets produced wrong event type")
  178. }
  179. actual := evt.Lease.Key()
  180. if actual != expected {
  181. t.Errorf("WatchSubnet produced wrong subnet: expected %s, got %s", expected, actual)
  182. }
  183. }
  184. func TestWatchLeaseRemoved(t *testing.T) {
  185. msr := newMockSubnetRegistry(0)
  186. sm := newEtcdManager(msr)
  187. ctx, cancel := context.WithCancel(context.Background())
  188. defer cancel()
  189. events := make(chan []Event)
  190. go WatchLeases(ctx, sm, "", events)
  191. expected := "10.3.4.0-24"
  192. msr.delCh <- expected
  193. evtBatch, ok := <-events
  194. if !ok {
  195. t.Fatalf("WatchSubnets did not publish")
  196. }
  197. if len(evtBatch) != 1 {
  198. t.Fatalf("WatchSubnets produced wrong sized event batch")
  199. }
  200. evt := evtBatch[0]
  201. if evt.Type != SubnetRemoved {
  202. t.Fatalf("WatchSubnets produced wrong event type")
  203. }
  204. actual := evt.Lease.Key()
  205. if actual != expected {
  206. t.Errorf("WatchSubnet produced wrong subnet: expected %s, got %s", expected, actual)
  207. }
  208. }
  209. type leaseData struct {
  210. Dummy string
  211. }
  212. func TestRenewLease(t *testing.T) {
  213. msr := newMockSubnetRegistry(1)
  214. sm := newEtcdManager(msr)
  215. // Create LeaseAttrs
  216. extIP, _ := ip.ParseIP4("1.2.3.4")
  217. attrs := LeaseAttrs{
  218. PublicIP: extIP,
  219. BackendType: "vxlan",
  220. }
  221. ld, err := json.Marshal(&leaseData{Dummy: "test string"})
  222. if err != nil {
  223. t.Fatalf("Failed to marshal leaseData: %v", err)
  224. }
  225. attrs.BackendData = json.RawMessage(ld)
  226. // Acquire lease
  227. ctx, cancel := context.WithCancel(context.Background())
  228. defer cancel()
  229. l, err := sm.AcquireLease(ctx, "", &attrs)
  230. if err != nil {
  231. t.Fatal("AcquireLease failed: ", err)
  232. }
  233. go LeaseRenewer(ctx, sm, "", l)
  234. fmt.Println("Waiting for lease to pass original expiration")
  235. time.Sleep(2 * time.Second)
  236. // check that it's still good
  237. for _, n := range msr.subnets.Nodes {
  238. if n.Key == l.Subnet.StringSep(".", "-") {
  239. if n.Expiration.Before(time.Now()) {
  240. t.Error("Failed to renew lease: expiration did not advance")
  241. }
  242. a := LeaseAttrs{}
  243. if err := json.Unmarshal([]byte(n.Value), &a); err != nil {
  244. t.Errorf("Failed to JSON-decode LeaseAttrs: %v", err)
  245. return
  246. }
  247. if !reflect.DeepEqual(a, attrs) {
  248. t.Errorf("LeaseAttrs changed: was %#v, now %#v", attrs, a)
  249. }
  250. return
  251. }
  252. }
  253. t.Fatalf("Failed to find acquired lease")
  254. }