func TestWatchLeaseAdded(t *testing.T) { msr := newDummyRegistry() sm := NewMockManager(msr) ctx, cancel := context.WithCancel(context.Background()) defer cancel() l := acquireLease(ctx, t, sm) events := make(chan []Event) go WatchLeases(ctx, sm, "_", l, events) evtBatch := <-events for _, evt := range evtBatch { if evt.Lease.Key() == l.Key() { t.Errorf("WatchLeases returned our own lease") } } expected := ip.IP4Net{ IP: ip.MustParseIP4("10.3.30.0"), PrefixLen: 24, } // Sanity check to make sure acquired lease is not this. // It shouldn't be as SubnetMin/SubnetMax in config is [10.3.1.0/24 to 10.3.25.0/24] if l.Subnet.Equal(expected) { t.Fatalf("Acquired lease conflicts with one about to create") } attrs := &LeaseAttrs{ PublicIP: ip.MustParseIP4("1.1.1.1"), } _, err := msr.createSubnet(ctx, "_", expected, attrs, 0) if err != nil { t.Fatalf("createSubnet filed: %v", err) } evtBatch = <-events if len(evtBatch) != 1 { t.Fatalf("WatchLeases produced wrong sized event batch: got %v, expected 1", len(evtBatch)) } evt := evtBatch[0] if evt.Type != EventAdded { t.Fatalf("WatchLeases produced wrong event type") } actual := evt.Lease.Subnet if !actual.Equal(expected) { t.Errorf("WatchSubnet produced wrong subnet: expected %s, got %s", expected, actual) } }
func TestRemoveReservation(t *testing.T) { msr := newDummyRegistry() sm := NewMockManager(msr) ctx, cancel := context.WithCancel(context.Background()) defer cancel() r := Reservation{ Subnet: newIP4Net("10.3.10.0", 24), PublicIP: ip.MustParseIP4("52.195.12.13"), } if err := sm.AddReservation(ctx, "_", &r); err != nil { t.Fatalf("failed to add reservation: %v", err) } if err := sm.RemoveReservation(ctx, "_", r.Subnet); err != nil { t.Fatalf("failed to remove reservation: %v", err) } // The node should have a TTL sub, _, err := msr.getSubnet(ctx, "_", r.Subnet) if err != nil { t.Fatalf("getSubnet failed: %v", err) } if sub.Expiration.IsZero() { t.Fatalf("removed reservation resulted in no TTL") } }
func TestAddReservation(t *testing.T) { msr := newDummyRegistry() sm := NewMockManager(msr) ctx, cancel := context.WithCancel(context.Background()) defer cancel() r := Reservation{ Subnet: newIP4Net("10.4.3.0", 24), PublicIP: ip.MustParseIP4("52.195.12.13"), } if err := sm.AddReservation(ctx, "_", &r); err == nil { t.Fatalf("unexpectedly added a reservation outside of configured network") } r.Subnet = newIP4Net("10.3.10.0", 24) if err := sm.AddReservation(ctx, "_", &r); err != nil { t.Fatalf("failed to add reservation: %v", err) } // Add the same reservation -- should succeed if err := sm.AddReservation(ctx, "_", &r); err != nil { t.Fatalf("failed to add reservation: %v", err) } // Add a reservation with a different public IP -- should fail r2 := r r2.PublicIP = ip.MustParseIP4("52.195.12.17") if err := sm.AddReservation(ctx, "_", &r2); err != ErrLeaseTaken { t.Fatalf("taken add reservation returned: %v", err) } attrs := &LeaseAttrs{ PublicIP: r.PublicIP, } l, err := sm.AcquireLease(ctx, "_", attrs) if err != nil { t.Fatalf("failed to acquire subnet: %v", err) } if !l.Subnet.Equal(r.Subnet) { t.Fatalf("acquired subnet is not the reserved one: expected %v, got %v", r.Subnet, l.Subnet) } if !l.Expiration.IsZero() { t.Fatalf("acquired lease (prev reserved) has expiration set") } }
func newDummyRegistry() *MockSubnetRegistry { attrs := LeaseAttrs{ PublicIP: ip.MustParseIP4("1.1.1.1"), } exp := time.Time{} subnets := []Lease{ {ip.IP4Net{ip.MustParseIP4("10.3.1.0"), 24}, attrs, exp, 10}, {ip.IP4Net{ip.MustParseIP4("10.3.2.0"), 24}, attrs, exp, 11}, {ip.IP4Net{ip.MustParseIP4("10.3.4.0"), 24}, attrs, exp, 12}, {ip.IP4Net{ip.MustParseIP4("10.3.5.0"), 24}, attrs, exp, 13}, } config := `{ "Network": "10.3.0.0/16", "SubnetMin": "10.3.1.0", "SubnetMax": "10.3.25.0" }` return NewMockRegistry("_", config, subnets) }
func TestWatchLeaseAdded(t *testing.T) { msr := newDummyRegistry() sm := NewMockManager(msr) ctx, cancel := context.WithCancel(context.Background()) defer cancel() l := acquireLease(ctx, t, sm) events := make(chan []Event) go WatchLeases(ctx, sm, "_", l, events) evtBatch := <-events for _, evt := range evtBatch { if evt.Lease.Key() == l.Key() { t.Errorf("WatchLeases returned our own lease") } } expected := ip.IP4Net{ IP: ip.MustParseIP4("10.3.6.0"), PrefixLen: 24, } attrs := &LeaseAttrs{ PublicIP: ip.MustParseIP4("1.1.1.1"), } msr.createSubnet(ctx, "_", expected, attrs, 0) evtBatch = <-events if len(evtBatch) != 1 { t.Fatalf("WatchLeases produced wrong sized event batch") } evt := evtBatch[0] if evt.Type != EventAdded { t.Fatalf("WatchLeases produced wrong event type") } actual := evt.Lease.Subnet if !actual.Equal(expected) { t.Errorf("WatchSubnet produced wrong subnet: expected %s, got %s", expected, actual) } }
func TestListReservations(t *testing.T) { msr := newDummyRegistry() sm := NewMockManager(msr) ctx, cancel := context.WithCancel(context.Background()) defer cancel() r1 := Reservation{ Subnet: newIP4Net("10.3.10.0", 24), PublicIP: ip.MustParseIP4("52.195.12.13"), } if err := sm.AddReservation(ctx, "_", &r1); err != nil { t.Fatalf("failed to add reservation: %v", err) } r2 := Reservation{ Subnet: newIP4Net("10.3.20.0", 24), PublicIP: ip.MustParseIP4("52.195.12.14"), } if err := sm.AddReservation(ctx, "_", &r2); err != nil { t.Fatalf("failed to add reservation: %v", err) } rs, err := sm.ListReservations(ctx, "_") if err != nil { if len(rs) != 2 { t.Fatalf("unexpected number of reservations, expected 2, got %v", len(rs)) } if !resvEqual(rs[0], r1) && !resvEqual(rs[1], r1) { t.Fatalf("reservation not found") } if !resvEqual(rs[0], r2) && !resvEqual(rs[1], r2) { t.Fatalf("reservation not found") } } }
func newDummyRegistry() *MockSubnetRegistry { attrs := LeaseAttrs{ PublicIP: ip.MustParseIP4("1.1.1.1"), } exp := time.Time{} subnets := []Lease{ // leases within SubnetMin-SubnetMax range {ip.IP4Net{ip.MustParseIP4("10.3.1.0"), 24}, attrs, exp, 10}, {ip.IP4Net{ip.MustParseIP4("10.3.2.0"), 24}, attrs, exp, 11}, {ip.IP4Net{ip.MustParseIP4("10.3.4.0"), 24}, attrs, exp, 12}, {ip.IP4Net{ip.MustParseIP4("10.3.5.0"), 24}, attrs, exp, 13}, // hand created lease outside the range of subnetMin-SubnetMax for testing removal {ip.IP4Net{ip.MustParseIP4("10.3.31.0"), 24}, attrs, exp, 13}, } config := `{ "Network": "10.3.0.0/16", "SubnetMin": "10.3.1.0", "SubnetMax": "10.3.25.0" }` return NewMockRegistry("_", config, subnets) }
func TestEtcdRegistry(t *testing.T) { r, m := newTestEtcdRegistry(t) ctx, _ := context.WithCancel(context.Background()) networks, _, err := r.getNetworks(ctx) if err != nil { t.Fatal("Failed to get networks") } if len(networks) != 0 { t.Fatal("Networks should be empty") } // Populate etcd with a network netKey := "/coreos.com/network/foobar/config" netValue := "{ \"Network\": \"10.1.0.0/16\", \"Backend\": { \"Type\": \"host-gw\" } }" m.Create(ctx, netKey, netValue) networks, _, err = r.getNetworks(ctx) if err != nil { t.Fatal("Failed to get networks the second time") } if len(networks) != 1 { t.Fatal("Failed to find expected network foobar") } config, err := r.getNetworkConfig(ctx, "foobar") if err != nil { t.Fatal("Failed to get network config") } if config != netValue { t.Fatal("Failed to match network config") } sn := ip.IP4Net{ IP: ip.MustParseIP4("10.1.5.0"), PrefixLen: 24, } wg := sync.WaitGroup{} wg.Add(1) startWg := sync.WaitGroup{} startWg.Add(1) result := make(chan error, 1) go func() { startWg.Done() watchSubnets(t, r, ctx, sn, m.index, result) wg.Done() }() startWg.Wait() // Lease a subnet for the network attrs := &LeaseAttrs{ PublicIP: ip.MustParseIP4("1.2.3.4"), } exp, err := r.createSubnet(ctx, "foobar", sn, attrs, 24*time.Hour) if err != nil { t.Fatal("Failed to create subnet lease") } if !exp.After(time.Now()) { t.Fatal("Subnet lease duration %v not in the future", exp) } // Make sure the lease got created resp, err := m.Get(ctx, "/coreos.com/network/foobar/subnets/10.1.5.0-24", nil) if err != nil { t.Fatal("Failed to verify subnet lease directly in etcd: %v", err) } if resp == nil || resp.Node == nil { t.Fatal("Failed to retrive node in subnet lease") } if resp.Node.Value != "{\"PublicIP\":\"1.2.3.4\"}" { t.Fatal("Unexpected subnet lease node %s value %s", resp.Node.Key, resp.Node.Value) } leases, _, err := r.getSubnets(ctx, "foobar") if len(leases) != 1 { t.Fatalf("Unexpected number of leases %d (expected 1)", len(leases)) } if !leases[0].Subnet.Equal(sn) { t.Fatalf("Mismatched subnet %v (expected %v)", leases[0].Subnet, sn) } lease, _, err := r.getSubnet(ctx, "foobar", sn) if lease == nil { t.Fatal("Missing subnet lease") } err = r.deleteSubnet(ctx, "foobar", sn) if err != nil { t.Fatalf("Failed to delete subnet %v: %v", sn, err) } // Make sure the lease got deleted resp, err = m.Get(ctx, "/coreos.com/network/foobar/subnets/10.1.5.0-24", nil) if err == nil { t.Fatal("Unexpected success getting deleted subnet") } wg.Wait() // Check errors from watch goroutine watchResult := <-result if watchResult != nil { t.Fatalf("Error watching keys: %v", watchResult) } // TODO: watchSubnet and watchNetworks }