func TestWatchNetworkAdded(t *testing.T) { msr := newDummyRegistry() sm := NewMockManager(msr) ctx, cancel := context.WithCancel(context.Background()) defer cancel() events := make(chan []Event) go WatchNetworks(ctx, sm, events) // skip over the initial snapshot <-events expected := "foobar" msr.CreateNetwork(ctx, expected, `{"Network": "10.1.1.0/16", "Backend": {"Type": "bridge"}}`) evtBatch := <-events if len(evtBatch) != 1 { t.Fatalf("WatchNetworks produced wrong sized event batch") } evt := evtBatch[0] if evt.Type != EventAdded { t.Fatalf("WatchNetworks produced wrong event type") } actual := evt.Network if actual != expected { t.Errorf("WatchNetworks produced wrong network: expected %s, got %s", expected, actual) } }
func TestWatchLeaseRemoved(t *testing.T) { msr := newDummyRegistry(0) sm := newEtcdManager(msr) ctx, cancel := context.WithCancel(context.Background()) defer cancel() events := make(chan []Event) go WatchLeases(ctx, sm, "", events) // skip over the initial snapshot <-events expected := "10.3.4.0-24" msr.expireSubnet(expected) evtBatch := <-events if len(evtBatch) != 1 { t.Fatalf("WatchSubnets produced wrong sized event batch") } evt := evtBatch[0] if evt.Type != SubnetRemoved { t.Fatalf("WatchSubnets produced wrong event type") } actual := evt.Lease.Key() if actual != expected { t.Errorf("WatchSubnet produced wrong subnet: expected %s, got %s", expected, actual) } }
func TestSimpleHTTPClientDoCancelContextWaitForRoundTrip(t *testing.T) { tr := newFakeTransport() c := &simpleHTTPClient{transport: tr} donechan := make(chan struct{}) ctx, cancel := context.WithCancel(context.Background()) go func() { c.Do(ctx, &fakeAction{}) close(donechan) }() // This should call CancelRequest and begin the cancellation process cancel() select { case <-donechan: t.Fatalf("simpleHTTPClient.Do should not have exited yet") default: } tr.finishCancel <- struct{}{} select { case <-donechan: //expected behavior return case <-time.After(time.Second): t.Fatalf("simpleHTTPClient.Do did not exit within 1s") } }
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 TestSimpleHTTPClientDoCancelContextResponseBodyClosed(t *testing.T) { tr := newFakeTransport() c := &simpleHTTPClient{transport: tr} // create an already-cancelled context ctx, cancel := context.WithCancel(context.Background()) cancel() body := &checkableReadCloser{ReadCloser: ioutil.NopCloser(strings.NewReader("foo"))} go func() { // wait that simpleHTTPClient knows the context is already timed out, // and calls CancelRequest testutil.WaitSchedule() // response is returned before cancel effects tr.respchan <- &http.Response{Body: body} }() _, _, err := c.Do(ctx, &fakeAction{}) if err == nil { t.Fatalf("expected non-nil error, got nil") } if !body.closed { t.Fatalf("expected closed body") } }
func TestWatchGetNetworks(t *testing.T) { msr := newDummyRegistry() sm := NewMockManager(msr) ctx, cancel := context.WithCancel(context.Background()) defer cancel() // Kill the previously added "_" network msr.DeleteNetwork(ctx, "_") expected := "foobar" msr.CreateNetwork(ctx, expected, `{"Network": "10.1.1.0/16", "Backend": {"Type": "bridge"}}`) resp, err := sm.WatchNetworks(ctx, nil) if err != nil { t.Errorf("WatchNetworks(nil) failed:", err) } if len(resp.Snapshot) != 1 { t.Errorf("WatchNetworks(nil) produced wrong number of networks: expected 1, got %d", len(resp.Snapshot)) } if resp.Snapshot[0] != expected { t.Errorf("WatchNetworks(nil) produced wrong network: expected %s, got %s", expected, resp.Snapshot[0]) } }
func doTestWatchNetworks(t *testing.T, sm subnet.Manager, serverRegistry *subnet.MockSubnetRegistry) { ctx, cancel := context.WithCancel(context.Background()) wg := sync.WaitGroup{} wg.Add(1) defer func() { cancel() wg.Wait() }() events := make(chan []subnet.Event) go func() { subnet.WatchNetworks(ctx, sm, events) wg.Done() }() // skip over the initial snapshot <-events expectedNetname := "foobar" config := fmt.Sprintf(`{"Network": %q}`, expectedNetwork) err := serverRegistry.CreateNetwork(ctx, expectedNetname, config) if err != nil { t.Errorf("create network failed: %v", err) } evtBatch := <-events if len(evtBatch) != 1 { t.Fatalf("WatchNetworks create produced wrong sized event batch") } evt := evtBatch[0] if evt.Type != subnet.EventAdded { t.Fatalf("WatchNetworks create produced wrong event type") } if evt.Network != expectedNetname { t.Errorf("WatchNetwork create produced wrong network: expected %s, got %s", expectedNetname, evt.Network) } err = serverRegistry.DeleteNetwork(ctx, expectedNetname) if err != nil { t.Errorf("delete network failed: %v", err) } evtBatch = <-events if len(evtBatch) != 1 { t.Fatalf("WatchNetworks delete produced wrong sized event batch") } evt = evtBatch[0] if evt.Type != subnet.EventRemoved { t.Fatalf("WatchNetworks delete produced wrong event type") } if evt.Network != expectedNetname { t.Errorf("WatchNetwork delete produced wrong network: expected %s, got %s", expectedNetname, evt.Network) } }
func TestRenewLease(t *testing.T) { msr := newDummyRegistry() sm := NewMockManager(msr) now := time.Now() fakeClock := clockwork.NewFakeClockAt(now) clock = fakeClock // Create LeaseAttrs extIaddr, _ := ip.ParseIP4("1.2.3.4") attrs := LeaseAttrs{ PublicIP: extIaddr, BackendType: "vxlan", } ld, err := json.Marshal(&leaseData{Dummy: "test string"}) if err != nil { t.Fatalf("Failed to marshal leaseData: %v", err) } attrs.BackendData = json.RawMessage(ld) // Acquire lease ctx, cancel := context.WithCancel(context.Background()) defer cancel() l, err := sm.AcquireLease(ctx, "_", &attrs) if err != nil { t.Fatal("AcquireLease failed: ", err) } now = now.Add(subnetTTL) fakeClock.Advance(24 * time.Hour) if err := sm.RenewLease(ctx, "_", l); err != nil { t.Fatal("RenewLease failed: ", err) } // check that it's still good n, err := msr.getNetwork(ctx, "_") if err != nil { t.Error("Failed to renew lease: could not get networks: %v", err) } for _, sn := range n.subnets { if sn.Subnet.Equal(l.Subnet) { expected := now.Add(subnetTTL) if !sn.Expiration.Equal(expected) { t.Errorf("Failed to renew lease: bad expiration; expected %v, got %v", expected, sn.Expiration) } if !reflect.DeepEqual(sn.Attrs, attrs) { t.Errorf("LeaseAttrs changed: was %#v, now %#v", attrs, sn.Attrs) } return } } t.Fatalf("Failed to find acquired lease") }
func New(sm subnet.Manager, network string) backend.Backend { ctx, cancel := context.WithCancel(context.Background()) return &AllocBackend{ sm: sm, network: network, ctx: ctx, cancel: cancel, } }
func TestRenewLease(t *testing.T) { msr := newDummyRegistry(1) sm := newEtcdManager(msr) // Create LeaseAttrs extIaddr, _ := ip.ParseIP4("1.2.3.4") attrs := LeaseAttrs{ PublicIP: extIaddr, BackendType: "vxlan", } ld, err := json.Marshal(&leaseData{Dummy: "test string"}) if err != nil { t.Fatalf("Failed to marshal leaseData: %v", err) } attrs.BackendData = json.RawMessage(ld) // Acquire lease ctx, cancel := context.WithCancel(context.Background()) defer cancel() l, err := sm.AcquireLease(ctx, "_", &attrs) if err != nil { t.Fatal("AcquireLease failed: ", err) } go LeaseRenewer(ctx, sm, "_", l) fmt.Println("Waiting for lease to pass original expiration") time.Sleep(2 * time.Second) // check that it's still good net, err := msr.getNetwork(ctx, "_") if err != nil { t.Error("Failed to renew lease: could not get networks: %v", err) } for _, n := range net.Node.Nodes { if n.Key == l.Subnet.StringSep(".", "-") { if n.Expiration.Before(time.Now()) { t.Error("Failed to renew lease: expiration did not advance") } a := LeaseAttrs{} if err := json.Unmarshal([]byte(n.Value), &a); err != nil { t.Errorf("Failed to JSON-decode LeaseAttrs: %v", err) return } if !reflect.DeepEqual(a, attrs) { t.Errorf("LeaseAttrs changed: was %#v, now %#v", attrs, a) } return } } t.Fatalf("Failed to find acquired lease") }
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 NewNetwork(ctx context.Context, sm subnet.Manager, name string, ipMasq bool) *Network { ctx, cancel := context.WithCancel(ctx) return &Network{ Name: name, ctx: ctx, cancelFunc: cancel, sm: sm, ipMasq: ipMasq, } }
func New(sm subnet.Manager, network string, config *subnet.Config) backend.Backend { ctx, cancel := context.WithCancel(context.Background()) gb := GCEBackend{ sm: sm, config: config, ctx: ctx, cancel: cancel, network: network, } return &gb }
func New(sm subnet.Manager, network string, config *subnet.Config) backend.Backend { ctx, cancel := context.WithCancel(context.Background()) be := AwsVpcBackend{ sm: sm, network: network, config: config, ctx: ctx, cancel: cancel, } return &be }
func New(sm subnet.Manager, network string, config *subnet.Config) backend.Backend { ctx, cancel := context.WithCancel(context.Background()) be := UdpBackend{ sm: sm, network: network, config: config, ctx: ctx, cancel: cancel, } be.cfg.Port = defaultPort return &be }
func New(sm subnet.Manager, network string, config *subnet.Config) backend.Backend { ctx, cancel := context.WithCancel(context.Background()) vb := &VXLANBackend{ sm: sm, network: network, config: config, ctx: ctx, cancel: cancel, } vb.cfg.VNI = defaultVNI return vb }
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 doTestWatch(t *testing.T, sm subnet.Manager) { ctx, cancel := context.WithCancel(context.Background()) wg := sync.WaitGroup{} wg.Add(1) defer func() { cancel() wg.Wait() }() events := make(chan []subnet.Event) go func() { subnet.WatchLeases(ctx, sm, "_", nil, events) wg.Done() }() // skip over the initial snapshot <-events attrs := &subnet.LeaseAttrs{ PublicIP: mustParseIP4("1.1.1.2"), } l, err := sm.AcquireLease(ctx, "_", attrs) if err != nil { t.Errorf("AcquireLease failed: %v", err) return } if !mustParseIP4Net(expectedNetwork).Contains(l.Subnet.IP) { t.Errorf("AcquireLease returned subnet not in network: %v (in %v)", l.Subnet, expectedNetwork) } evtBatch := <-events if len(evtBatch) != 1 { t.Fatalf("WatchSubnets produced wrong sized event batch") } evt := evtBatch[0] if evt.Type != subnet.SubnetAdded { t.Fatalf("WatchSubnets produced wrong event type") } if evt.Lease.Key() != l.Key() { t.Errorf("WatchSubnet produced wrong subnet: expected %s, got %s", l.Key(), evt.Lease.Key()) } }
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 newFixture(t *testing.T) *fixture { f := &fixture{} config := fmt.Sprintf(`{"Network": %q}`, expectedNetwork) f.registry = subnet.NewMockRegistry("", config, nil) sm := subnet.NewMockManager(f.registry) f.srvAddr = "127.0.0.1:9999" f.ctx, f.cancel = context.WithCancel(context.Background()) f.wg.Add(1) go func() { RunServer(f.ctx, sm, f.srvAddr, "", "", "") f.wg.Done() }() var err error f.sm, err = NewRemoteManager(f.srvAddr, "", "", "") if err != nil { panic(fmt.Sprintf("Failed to create remote mananager: %v", err)) } for i := 0; ; i++ { _, err := f.sm.GetNetworkConfig(f.ctx, "_") if err == nil { break } if isConnRefused(err) { if i == 100 { t.Fatalf("Out of connection retries") } fmt.Println("Connection refused, retrying...") time.Sleep(300 * time.Millisecond) continue } t.Fatalf("GetNetworkConfig failed: %v", err) } return f }
func TestRemote(t *testing.T) { config := fmt.Sprintf(`{"Network": %q}`, expectedNetwork) sm := subnet.NewMockManager(1, config) addr := "127.0.0.1:9999" ctx, cancel := context.WithCancel(context.Background()) wg := sync.WaitGroup{} wg.Add(1) go func() { RunServer(ctx, sm, addr, "", "", "") wg.Done() }() doTestRemote(ctx, t, addr) cancel() wg.Wait() }
func TestWatchNetworkRemoved(t *testing.T) { msr := newDummyRegistry(0) sm := newEtcdManager(msr) ctx, cancel := context.WithCancel(context.Background()) defer cancel() events := make(chan []Event) go WatchNetworks(ctx, sm, events) // skip over the initial snapshot <-events expected := "blah" msr.CreateNetwork(ctx, expected, `{"Network": "10.1.1.0/16", "Backend": {"Type": "bridge"}}`) // skip over the create event <-events _, err := msr.DeleteNetwork(ctx, expected) if err != nil { t.Fatalf("WatchNetworks failed to delete the network") } evtBatch := <-events if len(evtBatch) != 1 { t.Fatalf("WatchNetworks produced wrong sized event batch") } evt := evtBatch[0] if evt.Type != EventRemoved { t.Fatalf("WatchNetworks produced wrong event type") } actual := evt.Network if actual != expected { t.Errorf("WatchNetwork produced wrong network: expected %s, got %s", expected, actual) } }
func TestLeaseRevoked(t *testing.T) { msr := newDummyRegistry() sm := NewMockManager(msr) ctx, cancel := context.WithCancel(context.Background()) defer cancel() l := acquireLease(ctx, t, sm) if err := sm.RevokeLease(ctx, "_", l.Subnet); err != nil { t.Fatalf("RevokeLease failed: %v", err) } _, _, err := msr.getSubnet(ctx, "_", l.Subnet) if err == nil { t.Fatalf("Revoked lease still exists") } if etcdErr, ok := err.(etcd.Error); ok && etcdErr.Code != etcd.ErrorCodeKeyNotFound { t.Fatalf("getSubnets after revoked lease returned unexpected error: %v", err) } }
func TestSimpleHTTPClientDoCancelContextResponseBodyClosedWithBlockingBody(t *testing.T) { tr := newFakeTransport() c := &simpleHTTPClient{transport: tr} ctx, cancel := context.WithCancel(context.Background()) body := &checkableReadCloser{ReadCloser: &blockingBody{c: make(chan struct{})}} go func() { tr.respchan <- &http.Response{Body: body} time.Sleep(2 * time.Millisecond) // cancel after the body is received cancel() }() _, _, err := c.Do(ctx, &fakeAction{}) if err == nil { t.Fatalf("expected non-nil error, got nil") } if !body.closed { t.Fatalf("expected closed body") } }
func TestWatchLeaseAdded(t *testing.T) { msr := newDummyRegistry(0) sm := newEtcdManager(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 := "10.3.6.0-24" msr.createSubnet(ctx, "_", expected, `{"PublicIP": "1.1.1.1"}`, 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.Key() if actual != expected { t.Errorf("WatchSubnet produced wrong subnet: expected %s, got %s", expected, actual) } }
func TestHTTPClusterClientAutoSyncCancelContext(t *testing.T) { cf := newStaticHTTPClientFactory([]staticHTTPResponse{ { resp: http.Response{StatusCode: http.StatusOK, Header: http.Header{"Content-Type": []string{"application/json"}}}, body: []byte(`{"members":[{"id":"2745e2525fce8fe","peerURLs":["http://127.0.0.1:7003"],"name":"node3","clientURLs":["http://127.0.0.1:4003"]},{"id":"42134f434382925","peerURLs":["http://127.0.0.1:2380","http://127.0.0.1:7001"],"name":"node1","clientURLs":["http://127.0.0.1:2379","http://127.0.0.1:4001"]},{"id":"94088180e21eb87b","peerURLs":["http://127.0.0.1:7002"],"name":"node2","clientURLs":["http://127.0.0.1:4002"]}]}`), }, }) hc := &httpClusterClient{ clientFactory: cf, rand: rand.New(rand.NewSource(0)), } err := hc.reset([]string{"http://127.0.0.1:2379"}) if err != nil { t.Fatalf("unexpected error during setup: %#v", err) } ctx, cancel := context.WithCancel(context.Background()) cancel() err = hc.AutoSync(ctx, time.Hour) if err != context.Canceled { t.Fatalf("incorrect error value: want=%v got=%v", context.Canceled, err) } }
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 main() { // glog will log to tmp files by default. override so all entries // can flow into journald (if running under systemd) flag.Set("logtostderr", "true") // now parse command line args flag.Parse() if flag.NArg() > 0 || opts.help { fmt.Fprintf(os.Stderr, "Usage: %s [OPTION]...\n", os.Args[0]) flag.PrintDefaults() os.Exit(0) } if opts.version { fmt.Fprintln(os.Stderr, Version) os.Exit(0) } flagsFromEnv("FLANNELD", flag.CommandLine) sm, err := newSubnetManager() if err != nil { log.Error("Failed to create SubnetManager: ", err) os.Exit(1) } var runFunc func(ctx context.Context) if opts.listen != "" { if opts.remote != "" { log.Error("--listen and --remote are mutually exclusive") os.Exit(1) } log.Info("running as server") runFunc = func(ctx context.Context) { remote.RunServer(ctx, sm, opts.listen, opts.remoteCAFile, opts.remoteCertfile, opts.remoteKeyfile) } } else { networks := strings.Split(opts.networks, ",") if len(networks) == 0 { networks = append(networks, "") } runFunc = func(ctx context.Context) { initAndRun(ctx, sm, networks) } } // Register for SIGINT and SIGTERM log.Info("Installing signal handlers") sigs := make(chan os.Signal, 1) signal.Notify(sigs, os.Interrupt, syscall.SIGTERM) ctx, cancel := context.WithCancel(context.Background()) wg := sync.WaitGroup{} wg.Add(1) go func() { runFunc(ctx) wg.Done() }() <-sigs // unregister to get default OS nuke behaviour in case we don't exit cleanly signal.Stop(sigs) log.Info("Exiting...") cancel() wg.Wait() }
func (n *Network) runOnce(extIface *backend.ExternalInterface, inited func(bn backend.Network)) error { if err := n.retryInit(); err != nil { return errCanceled } inited(n.bn) ctx, interruptFunc := context.WithCancel(n.ctx) wg := sync.WaitGroup{} wg.Add(1) go func() { n.bn.Run(ctx) wg.Done() }() evts := make(chan subnet.Event) wg.Add(1) go func() { subnet.WatchLease(ctx, n.sm, n.Name, n.bn.Lease().Subnet, evts) wg.Done() }() defer func() { if n.ipMasq { if err := teardownIPMasq(n.Config.Network); err != nil { log.Errorf("Failed to tear down IP Masquerade for network %v: %v", n.Name, err) } } }() defer wg.Wait() dur := n.bn.Lease().Expiration.Sub(time.Now()) - renewMargin for { select { case <-time.After(dur): err := n.sm.RenewLease(n.ctx, n.Name, n.bn.Lease()) if err != nil { log.Error("Error renewing lease (trying again in 1 min): ", err) dur = time.Minute continue } log.Info("Lease renewed, new expiration: ", n.bn.Lease().Expiration) dur = n.bn.Lease().Expiration.Sub(time.Now()) - renewMargin case e := <-evts: switch e.Type { case subnet.EventAdded: n.bn.Lease().Expiration = e.Lease.Expiration dur = n.bn.Lease().Expiration.Sub(time.Now()) - renewMargin case subnet.EventRemoved: log.Warning("Lease has been revoked") interruptFunc() return errInterrupted } case <-n.ctx.Done(): return errCanceled } } }
func TestMockEtcd(t *testing.T) { m := newMockEtcd() ctx, _ := context.WithCancel(context.Background()) // Sanity tests for our mock etcd // Ensure no entries yet exist opts := &etcd.GetOptions{Recursive: true} r, err := m.Get(ctx, "/", opts) e := &etcd.Response{Action: "get", Index: 1000, Node: m.nodes["/"]} expectSuccess(t, r, err, e, "") // Create base test keys sopts := &etcd.SetOptions{Dir: true} r, err = m.Set(ctx, "/coreos.com/network", "", sopts) e = &etcd.Response{Action: "create", Index: 1002} expectSuccess(t, r, err, e, "") wopts := &etcd.WatcherOptions{AfterIndex: m.index, Recursive: true} watcher := m.Watcher("/coreos.com/network", wopts) result := make(chan error, 1) go watchMockEtcd(ctx, watcher, result) // Populate etcd with some keys netKey1 := "/coreos.com/network/foobar/config" netValue := "{ \"Network\": \"10.1.0.0/16\", \"Backend\": { \"Type\": \"host-gw\" } }" r, err = m.Create(ctx, netKey1, netValue) e = &etcd.Response{Action: "create", Index: 1004} expectSuccess(t, r, err, e, netValue) netKey2 := "/coreos.com/network/blah/config" netValue = "{ \"Network\": \"10.1.1.0/16\", \"Backend\": { \"Type\": \"host-gw\" } }" r, err = m.Create(ctx, netKey2, netValue) e = &etcd.Response{Action: "create", Index: 1006} expectSuccess(t, r, err, e, netValue) // Get it again expectedNode := r.Node opts = &etcd.GetOptions{Recursive: false} r, err = m.Get(ctx, netKey2, opts) e = &etcd.Response{Action: "get", Index: m.index, Node: expectedNode} expectSuccess(t, r, err, e, netValue) // Update it netValue = "ReallyCoolValue" r, err = m.Update(ctx, netKey2, netValue) e = &etcd.Response{Action: "update", Index: m.index} expectSuccess(t, r, err, e, netValue) // Get it again opts = &etcd.GetOptions{Recursive: false} r, err = m.Get(ctx, netKey2, opts) e = &etcd.Response{Action: "get", Index: m.index} expectSuccess(t, r, err, e, netValue) // test directory listing opts = &etcd.GetOptions{Recursive: true} r, err = m.Get(ctx, "/coreos.com/network/", opts) e = &etcd.Response{Action: "get", Index: 1007} expectSuccess(t, r, err, e, "") if len(r.Node.Nodes) != 2 { t.Fatalf("Unexpected %d children in response (expected 2)", len(r.Node.Nodes)) } node1Found := false node2Found := false for _, child := range r.Node.Nodes { if child.Dir != true { t.Fatalf("Unexpected non-directory child %s", child.Key) } if child.Key == "/coreos.com/network/foobar" { node1Found = true } else if child.Key == "/coreos.com/network/blah" { node2Found = true } else { t.Fatalf("Unexpected child %s found", child.Key) } if len(child.Nodes) != 1 { t.Fatalf("Unexpected %d children in response (expected 2)", len(r.Node.Nodes)) } } if node1Found == false || node2Found == false { t.Fatalf("Failed to find expected children") } // Delete a key dopts := &etcd.DeleteOptions{Recursive: true, Dir: false} r, err = m.Delete(ctx, "/coreos.com/network/foobar", dopts) if err == nil { t.Fatalf("Unexpected success deleting a directory") } // Delete a key dopts = &etcd.DeleteOptions{Recursive: true, Dir: true} r, err = m.Delete(ctx, "/coreos.com/network/foobar", dopts) e = &etcd.Response{Action: "delete", Index: 1010} expectSuccess(t, r, err, e, "") // Get it again; should fail opts = &etcd.GetOptions{Recursive: false} r, err = m.Get(ctx, netKey1, opts) if err == nil { t.Fatalf("Get of %s after delete unexpectedly succeeded", netKey1) } if r != nil { t.Fatalf("Unexpected non-nil response to get after delete %v", r) } // Check errors from watch goroutine watchResult := <-result if watchResult != nil { t.Fatalf("Error watching keys: %v", watchResult) } }