subnet_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. // Copyright 2015 flannel authors
  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 etcdv2
  15. import (
  16. "encoding/json"
  17. "reflect"
  18. "testing"
  19. "time"
  20. "github.com/coreos/flannel/pkg/ip"
  21. . "github.com/coreos/flannel/subnet"
  22. "github.com/jonboulle/clockwork"
  23. "golang.org/x/net/context"
  24. )
  25. func newDummyRegistry() *MockSubnetRegistry {
  26. attrs := LeaseAttrs{
  27. PublicIP: ip.MustParseIP4("1.1.1.1"),
  28. }
  29. exp := time.Time{}
  30. subnets := []Lease{
  31. // leases within SubnetMin-SubnetMax range
  32. {ip.IP4Net{ip.MustParseIP4("10.3.1.0"), 24}, attrs, exp, 10},
  33. {ip.IP4Net{ip.MustParseIP4("10.3.2.0"), 24}, attrs, exp, 11},
  34. {ip.IP4Net{ip.MustParseIP4("10.3.4.0"), 24}, attrs, exp, 12},
  35. {ip.IP4Net{ip.MustParseIP4("10.3.5.0"), 24}, attrs, exp, 13},
  36. // hand created lease outside the range of subnetMin-SubnetMax for testing removal
  37. {ip.IP4Net{ip.MustParseIP4("10.3.31.0"), 24}, attrs, exp, 13},
  38. }
  39. config := `{ "Network": "10.3.0.0/16", "SubnetMin": "10.3.1.0", "SubnetMax": "10.3.25.0" }`
  40. return NewMockRegistry(config, subnets)
  41. }
  42. func TestAcquireLease(t *testing.T) {
  43. msr := newDummyRegistry()
  44. sm := NewMockManager(msr)
  45. extIaddr, _ := ip.ParseIP4("1.2.3.4")
  46. attrs := LeaseAttrs{
  47. PublicIP: extIaddr,
  48. }
  49. l, err := sm.AcquireLease(context.Background(), &attrs)
  50. if err != nil {
  51. t.Fatal("AcquireLease failed: ", err)
  52. }
  53. if !inAllocatableRange(context.Background(), sm, l.Subnet) {
  54. t.Fatal("Subnet mismatch: expected 10.3.3.0/24, got: ", l.Subnet)
  55. }
  56. // Acquire again, should reuse
  57. l2, err := sm.AcquireLease(context.Background(), &attrs)
  58. if err != nil {
  59. t.Fatal("AcquireLease failed: ", err)
  60. }
  61. if !l.Subnet.Equal(l2.Subnet) {
  62. t.Fatalf("AcquireLease did not reuse subnet; expected %v, got %v", l.Subnet, l2.Subnet)
  63. }
  64. // Test if a previous subnet will be used
  65. msr2 := newDummyRegistry()
  66. prevSubnet := ip.IP4Net{ip.MustParseIP4("10.3.6.0"), 24}
  67. sm2 := NewMockManagerWithSubnet(msr2, prevSubnet)
  68. prev, err := sm2.AcquireLease(context.Background(), &attrs)
  69. if err != nil {
  70. t.Fatal("AcquireLease failed: ", err)
  71. }
  72. if !prev.Subnet.Equal(prevSubnet) {
  73. t.Fatalf("AcquireLease did not reuse subnet from previous run; expected %v, got %v", prevSubnet, prev.Subnet)
  74. }
  75. // Test that a previous subnet will not be used if it does not match the registry config
  76. msr3 := newDummyRegistry()
  77. invalidSubnet := ip.IP4Net{ip.MustParseIP4("10.4.1.0"), 24}
  78. sm3 := NewMockManagerWithSubnet(msr3, invalidSubnet)
  79. l3, err := sm3.AcquireLease(context.Background(), &attrs)
  80. if err != nil {
  81. t.Fatal("AcquireLease failed: ", err)
  82. }
  83. if l3.Subnet.Equal(invalidSubnet) {
  84. t.Fatalf("AcquireLease reused invalid subnet from previous run; reused %v", l3.Subnet)
  85. }
  86. }
  87. func TestConfigChanged(t *testing.T) {
  88. msr := newDummyRegistry()
  89. sm := NewMockManager(msr)
  90. extIaddr, _ := ip.ParseIP4("1.2.3.4")
  91. attrs := LeaseAttrs{
  92. PublicIP: extIaddr,
  93. }
  94. l, err := sm.AcquireLease(context.Background(), &attrs)
  95. if err != nil {
  96. t.Fatal("AcquireLease failed: ", err)
  97. }
  98. if !inAllocatableRange(context.Background(), sm, l.Subnet) {
  99. t.Fatal("Acquired subnet outside of valid range: ", l.Subnet)
  100. }
  101. // Change config
  102. config := `{ "Network": "10.4.0.0/16" }`
  103. msr.setConfig(config)
  104. // Acquire again, should not reuse
  105. if l, err = sm.AcquireLease(context.Background(), &attrs); err != nil {
  106. t.Fatal("AcquireLease failed: ", err)
  107. }
  108. if !inAllocatableRange(context.Background(), sm, l.Subnet) {
  109. t.Fatal("Acquired subnet outside of valid range: ", l.Subnet)
  110. }
  111. }
  112. func newIP4Net(ipaddr string, prefix uint) ip.IP4Net {
  113. a, err := ip.ParseIP4(ipaddr)
  114. if err != nil {
  115. panic("failed to parse ipaddr")
  116. }
  117. return ip.IP4Net{
  118. IP: a,
  119. PrefixLen: prefix,
  120. }
  121. }
  122. func acquireLease(ctx context.Context, t *testing.T, sm Manager) *Lease {
  123. extIaddr, _ := ip.ParseIP4("1.2.3.4")
  124. attrs := LeaseAttrs{
  125. PublicIP: extIaddr,
  126. }
  127. l, err := sm.AcquireLease(ctx, &attrs)
  128. if err != nil {
  129. t.Fatal("AcquireLease failed: ", err)
  130. }
  131. return l
  132. }
  133. func TestWatchLeaseAdded(t *testing.T) {
  134. msr := newDummyRegistry()
  135. sm := NewMockManager(msr)
  136. ctx, cancel := context.WithCancel(context.Background())
  137. defer cancel()
  138. l := acquireLease(ctx, t, sm)
  139. events := make(chan []Event)
  140. go WatchLeases(ctx, sm, l, events)
  141. evtBatch := <-events
  142. for _, evt := range evtBatch {
  143. if evt.Lease.Key() == l.Key() {
  144. t.Errorf("WatchLeases returned our own lease")
  145. }
  146. }
  147. expected := ip.IP4Net{
  148. IP: ip.MustParseIP4("10.3.30.0"),
  149. PrefixLen: 24,
  150. }
  151. // Sanity check to make sure acquired lease is not this.
  152. // It shouldn't be as SubnetMin/SubnetMax in config is [10.3.1.0/24 to 10.3.25.0/24]
  153. if l.Subnet.Equal(expected) {
  154. t.Fatalf("Acquired lease conflicts with one about to create")
  155. }
  156. attrs := &LeaseAttrs{
  157. PublicIP: ip.MustParseIP4("1.1.1.1"),
  158. }
  159. _, err := msr.createSubnet(ctx, expected, attrs, 0)
  160. if err != nil {
  161. t.Fatalf("createSubnet filed: %v", err)
  162. }
  163. evtBatch = <-events
  164. if len(evtBatch) != 1 {
  165. t.Fatalf("WatchLeases produced wrong sized event batch: got %v, expected 1", len(evtBatch))
  166. }
  167. evt := evtBatch[0]
  168. if evt.Type != EventAdded {
  169. t.Fatalf("WatchLeases produced wrong event type")
  170. }
  171. actual := evt.Lease.Subnet
  172. if !actual.Equal(expected) {
  173. t.Errorf("WatchSubnet produced wrong subnet: expected %s, got %s", expected, actual)
  174. }
  175. }
  176. func TestWatchLeaseRemoved(t *testing.T) {
  177. msr := newDummyRegistry()
  178. sm := NewMockManager(msr)
  179. ctx, cancel := context.WithCancel(context.Background())
  180. defer cancel()
  181. l := acquireLease(ctx, t, sm)
  182. events := make(chan []Event)
  183. go WatchLeases(ctx, sm, l, events)
  184. evtBatch := <-events
  185. for _, evt := range evtBatch {
  186. if evt.Lease.Key() == l.Key() {
  187. t.Errorf("WatchLeases returned our own lease")
  188. }
  189. }
  190. expected := ip.IP4Net{ip.MustParseIP4("10.3.31.0"), 24}
  191. // Sanity check to make sure acquired lease is not this.
  192. // It shouldn't be as SubnetMin/SubnetMax in config is [10.3.1.0/24 to 10.3.25.0/24]
  193. if l.Subnet.Equal(expected) {
  194. t.Fatalf("Acquired lease conflicts with one about to create")
  195. }
  196. msr.expireSubnet("_", expected)
  197. evtBatch = <-events
  198. if len(evtBatch) != 1 {
  199. t.Fatalf("WatchLeases produced wrong sized event batch: %#v", evtBatch)
  200. }
  201. evt := evtBatch[0]
  202. if evt.Type != EventRemoved {
  203. t.Fatalf("WatchLeases produced wrong event type")
  204. }
  205. actual := evt.Lease.Subnet
  206. if !actual.Equal(expected) {
  207. t.Errorf("WatchSubnet produced wrong subnet: expected %s, got %s", expected, actual)
  208. }
  209. }
  210. type leaseData struct {
  211. Dummy string
  212. }
  213. func TestRenewLease(t *testing.T) {
  214. msr := newDummyRegistry()
  215. sm := NewMockManager(msr)
  216. now := time.Now()
  217. fakeClock := clockwork.NewFakeClockAt(now)
  218. clock = fakeClock
  219. // Create LeaseAttrs
  220. extIaddr, _ := ip.ParseIP4("1.2.3.4")
  221. attrs := LeaseAttrs{
  222. PublicIP: extIaddr,
  223. BackendType: "vxlan",
  224. }
  225. ld, err := json.Marshal(&leaseData{Dummy: "test string"})
  226. if err != nil {
  227. t.Fatalf("Failed to marshal leaseData: %v", err)
  228. }
  229. attrs.BackendData = json.RawMessage(ld)
  230. // Acquire lease
  231. ctx, cancel := context.WithCancel(context.Background())
  232. defer cancel()
  233. l, err := sm.AcquireLease(ctx, &attrs)
  234. if err != nil {
  235. t.Fatal("AcquireLease failed: ", err)
  236. }
  237. now = now.Add(subnetTTL)
  238. fakeClock.Advance(24 * time.Hour)
  239. if err := sm.RenewLease(ctx, l); err != nil {
  240. t.Fatal("RenewLease failed: ", err)
  241. }
  242. // check that it's still good
  243. n, err := msr.getNetwork(ctx)
  244. if err != nil {
  245. t.Errorf("Failed to renew lease: could not get networks: %v", err)
  246. }
  247. for _, sn := range n.subnets {
  248. if sn.Subnet.Equal(l.Subnet) {
  249. expected := now.Add(subnetTTL)
  250. if !sn.Expiration.Equal(expected) {
  251. t.Errorf("Failed to renew lease: bad expiration; expected %v, got %v", expected, sn.Expiration)
  252. }
  253. if !reflect.DeepEqual(sn.Attrs, attrs) {
  254. t.Errorf("LeaseAttrs changed: was %#v, now %#v", attrs, sn.Attrs)
  255. }
  256. return
  257. }
  258. }
  259. t.Fatal("Failed to find acquired lease")
  260. }
  261. func TestAddReservation(t *testing.T) {
  262. msr := newDummyRegistry()
  263. sm := NewMockManager(msr)
  264. ctx, cancel := context.WithCancel(context.Background())
  265. defer cancel()
  266. r := Reservation{
  267. Subnet: newIP4Net("10.4.3.0", 24),
  268. PublicIP: ip.MustParseIP4("52.195.12.13"),
  269. }
  270. if err := sm.AddReservation(ctx, &r); err == nil {
  271. t.Fatalf("unexpectedly added a reservation outside of configured network")
  272. }
  273. r.Subnet = newIP4Net("10.3.10.0", 24)
  274. if err := sm.AddReservation(ctx, &r); err != nil {
  275. t.Fatalf("failed to add reservation: %v", err)
  276. }
  277. // Add the same reservation -- should succeed
  278. if err := sm.AddReservation(ctx, &r); err != nil {
  279. t.Fatalf("failed to add reservation: %v", err)
  280. }
  281. // Add a reservation with a different public IP -- should fail
  282. r2 := r
  283. r2.PublicIP = ip.MustParseIP4("52.195.12.17")
  284. if err := sm.AddReservation(ctx, &r2); err != ErrLeaseTaken {
  285. t.Fatalf("taken add reservation returned: %v", err)
  286. }
  287. attrs := &LeaseAttrs{
  288. PublicIP: r.PublicIP,
  289. }
  290. l, err := sm.AcquireLease(ctx, attrs)
  291. if err != nil {
  292. t.Fatalf("failed to acquire subnet: %v", err)
  293. }
  294. if !l.Subnet.Equal(r.Subnet) {
  295. t.Fatalf("acquired subnet is not the reserved one: expected %v, got %v", r.Subnet, l.Subnet)
  296. }
  297. if !l.Expiration.IsZero() {
  298. t.Fatalf("acquired lease (prev reserved) has expiration set")
  299. }
  300. }
  301. func TestRemoveReservation(t *testing.T) {
  302. msr := newDummyRegistry()
  303. sm := NewMockManager(msr)
  304. ctx, cancel := context.WithCancel(context.Background())
  305. defer cancel()
  306. r := Reservation{
  307. Subnet: newIP4Net("10.3.10.0", 24),
  308. PublicIP: ip.MustParseIP4("52.195.12.13"),
  309. }
  310. if err := sm.AddReservation(ctx, &r); err != nil {
  311. t.Fatalf("failed to add reservation: %v", err)
  312. }
  313. if err := sm.RemoveReservation(ctx, r.Subnet); err != nil {
  314. t.Fatalf("failed to remove reservation: %v", err)
  315. }
  316. // The node should have a TTL
  317. sub, _, err := msr.getSubnet(ctx, r.Subnet)
  318. if err != nil {
  319. t.Fatalf("getSubnet failed: %v", err)
  320. }
  321. if sub.Expiration.IsZero() {
  322. t.Fatalf("removed reservation resulted in no TTL")
  323. }
  324. }
  325. func TestListReservations(t *testing.T) {
  326. msr := newDummyRegistry()
  327. sm := NewMockManager(msr)
  328. ctx, cancel := context.WithCancel(context.Background())
  329. defer cancel()
  330. r1 := Reservation{
  331. Subnet: newIP4Net("10.3.10.0", 24),
  332. PublicIP: ip.MustParseIP4("52.195.12.13"),
  333. }
  334. if err := sm.AddReservation(ctx, &r1); err != nil {
  335. t.Fatalf("failed to add reservation: %v", err)
  336. }
  337. r2 := Reservation{
  338. Subnet: newIP4Net("10.3.20.0", 24),
  339. PublicIP: ip.MustParseIP4("52.195.12.14"),
  340. }
  341. if err := sm.AddReservation(ctx, &r2); err != nil {
  342. t.Fatalf("failed to add reservation: %v", err)
  343. }
  344. rs, err := sm.ListReservations(ctx)
  345. if err != nil {
  346. if len(rs) != 2 {
  347. t.Fatalf("unexpected number of reservations, expected 2, got %v", len(rs))
  348. }
  349. if !resvEqual(rs[0], r1) && !resvEqual(rs[1], r1) {
  350. t.Fatalf("reservation not found")
  351. }
  352. if !resvEqual(rs[0], r2) && !resvEqual(rs[1], r2) {
  353. t.Fatalf("reservation not found")
  354. }
  355. }
  356. }
  357. func inAllocatableRange(ctx context.Context, sm Manager, ipn ip.IP4Net) bool {
  358. cfg, err := sm.GetNetworkConfig(ctx)
  359. if err != nil {
  360. panic(err)
  361. }
  362. return ipn.IP >= cfg.SubnetMin || ipn.IP <= cfg.SubnetMax
  363. }
  364. func resvEqual(r1, r2 Reservation) bool {
  365. return r1.Subnet.Equal(r2.Subnet) && r1.PublicIP == r2.PublicIP
  366. }