func (s *S) TestLeaderRouting(c *C) { srv1 := httptest.NewServer(httpTestHandler("1")) srv2 := httptest.NewServer(httpTestHandler("2")) defer srv1.Close() defer srv2.Close() l := s.newHTTPListener(c) defer l.Close() client := l.discoverd err := client.AddService("leader-routing-http", &discoverd.ServiceConfig{ LeaderType: discoverd.LeaderTypeManual, }) c.Assert(err, IsNil) addRoute(c, l, router.HTTPRoute{ Domain: "foo.bar", Service: "leader-routing-http", Leader: true, }.ToRoute()) discoverdRegisterHTTPService(c, l, "leader-routing-http", srv1.Listener.Addr().String()) discoverdRegisterHTTPService(c, l, "leader-routing-http", srv2.Listener.Addr().String()) discoverdSetLeaderHTTP(c, l, "leader-routing-http", md5sum("tcp-"+srv1.Listener.Addr().String())) assertGet(c, "http://"+l.Addr, "foo.bar", "1") discoverdSetLeaderHTTP(c, l, "leader-routing-http", md5sum("tcp-"+srv2.Listener.Addr().String())) c.Assert(err, IsNil) assertGet(c, "http://"+l.Addr, "foo.bar", "2") }
func main() { var config Config config.Backend.Type = "vxlan" if backend := os.Getenv("BACKEND"); backend != "" { config.Backend.Type = backend } config.Network = os.Getenv("NETWORK") if config.Network == "" { config.Network = "100.100.0.0/16" } flag.StringVar(&config.SubnetMin, "subnet-min", "", "container network min subnet") flag.StringVar(&config.SubnetMax, "subnet-max", "", "container network max subnet") flag.UintVar(&config.SubnetLen, "subnet-len", 0, "container network subnet length") flag.UintVar(&config.Backend.VNI, "vni", 0, "vxlan network identifier") flag.UintVar(&config.Backend.Port, "port", 0, "vxlan communication port (UDP)") flag.Parse() // wait for discoverd to come up status, err := cluster.WaitForHostStatus(os.Getenv("EXTERNAL_IP"), func(status *host.HostStatus) bool { return status.Discoverd != nil && status.Discoverd.URL != "" }) if err != nil { log.Fatal(err) } // create service and config if not present client := discoverd.NewClientWithURL(status.Discoverd.URL) if err := client.AddService(serviceName, nil); err != nil && !hh.IsObjectExistsError(err) { log.Fatalf("error creating discoverd service: %s", err) } data, err := json.Marshal(map[string]Config{"config": config}) if err != nil { log.Fatal(err) } err = client.Service(serviceName).SetMeta(&discoverd.ServiceMeta{Data: data}) if err != nil && !hh.IsObjectExistsError(err) { log.Fatalf("error creating discoverd service metadata: %s", err) } flanneld, err := exec.LookPath("flanneld") if err != nil { log.Fatal(err) } if err := syscall.Exec( flanneld, []string{ flanneld, "-discoverd-url=" + status.Discoverd.URL, "-iface=" + os.Getenv("EXTERNAL_IP"), "-http-port=" + os.Getenv("PORT"), fmt.Sprintf("-notify-url=http://%s:1113/host/network", os.Getenv("EXTERNAL_IP")), }, os.Environ(), ); err != nil { log.Fatal(err) } }
func newTest(t *testing.T) (s *test) { defer func() { if t.Failed() { s.cleanup() t.FailNow() } }() client, killDiscoverd := testutil.BootDiscoverd(t, "") serviceName := "flannel-test" if err := client.AddService(serviceName, nil); err != nil { t.Errorf("error adding service: %s", err) } service := client.Service(serviceName) events := make(chan *discoverd.Event) stream, err := service.Watch(events) if err != nil { t.Errorf("error creating watch: %s", err) } data := []byte(`{"config":{"network": "10.3.0.0/16"}}`) if err := service.SetMeta(&discoverd.ServiceMeta{Data: data}); err != nil { t.Errorf("error setting meta: %s", err) } registry, err := NewRegistry(client, serviceName) if err != nil { t.Errorf("error creating registry: %s", err) } return &test{ T: t, client: client, service: service, events: events, registry: registry, cleanup: func() { stream.Close() killDiscoverd() }, } }
func (s *S) TestTCPLeaderRouting(c *C) { portInt := allocatePort() port := strconv.Itoa(portInt) addr := "127.0.0.1:" + port srv1 := NewTCPTestServer("1") srv2 := NewTCPTestServer("2") defer srv1.Close() defer srv2.Close() l := s.newTCPListener(c) defer l.Close() client := l.discoverd err := client.AddService("leader-routing-tcp", &discoverd.ServiceConfig{ LeaderType: discoverd.LeaderTypeManual, }) c.Assert(err, IsNil) wait := waitForEvent(c, l, "set", "") r := router.TCPRoute{ Service: "leader-routing-tcp", Port: portInt, Leader: true, }.ToRoute() err = l.AddRoute(r) c.Assert(err, IsNil) wait() discoverdRegisterTCPService(c, l, "leader-routing-tcp", srv1.Addr) discoverdRegisterTCPService(c, l, "leader-routing-tcp", srv2.Addr) discoverdSetLeaderTCP(c, l, "leader-routing-tcp", md5sum("tcp-"+srv1.Addr)) assertTCPConn(c, addr, "1") discoverdSetLeaderTCP(c, l, "leader-routing-tcp", md5sum("tcp-"+srv2.Addr)) assertTCPConn(c, addr, "2") }
func monitor(port host.Port, container *ContainerInit, env map[string]string, log log15.Logger) (discoverd.Heartbeater, error) { config := port.Service client := discoverd.NewClientWithURL(env["DISCOVERD"]) client.Logger = logger.New("component", "discoverd") if config.Create { // TODO: maybe reuse maybeAddService() from the client log.Info("creating service") if err := client.AddService(config.Name, nil); err != nil { if !hh.IsObjectExistsError(err) { log.Error("error creating service", "err", err) return nil, fmt.Errorf("something went wrong with discoverd: %s", err) } } } inst := &discoverd.Instance{ Addr: fmt.Sprintf("%s:%v", env["EXTERNAL_IP"], port.Port), Proto: port.Proto, } // add discoverd.EnvInstanceMeta if present for k, v := range env { if _, ok := discoverd.EnvInstanceMeta[k]; !ok { continue } if inst.Meta == nil { inst.Meta = make(map[string]string) } inst.Meta[k] = v } // no checker, but we still want to register a service if config.Check == nil { log.Info("registering instance", "instance", inst) return client.RegisterInstance(config.Name, inst) } var check health.Check switch config.Check.Type { case "tcp": check = &health.TCPCheck{Addr: inst.Addr} case "http", "https": check = &health.HTTPCheck{ URL: fmt.Sprintf("%s://%s%s", config.Check.Type, inst.Addr, config.Check.Path), Host: config.Check.Host, StatusCode: config.Check.Status, MatchBytes: []byte(config.Check.Match), } default: // unsupported checker type return nil, fmt.Errorf("unsupported check type: %s", config.Check.Type) } log.Info("adding healthcheck", "type", config.Check.Type, "interval", config.Check.Interval, "threshold", config.Check.Threshold) reg := health.Registration{ Registrar: client, Service: config.Name, Instance: inst, Monitor: health.Monitor{ Interval: config.Check.Interval, Threshold: config.Check.Threshold, Logger: log.New("component", "monitor"), }.Run, Check: check, Logger: log, } if config.Check.KillDown { reg.Events = make(chan health.MonitorEvent) go func() { if config.Check.StartTimeout == 0 { config.Check.StartTimeout = 10 * time.Second } start := false lastStatus := health.MonitorStatusDown var mtx sync.Mutex maybeKill := func() { if lastStatus == health.MonitorStatusDown { log.Warn("killing the job") container.Signal(int(syscall.SIGKILL), &struct{}{}) } } go func() { // ignore events for the first StartTimeout interval <-time.After(config.Check.StartTimeout) mtx.Lock() defer mtx.Unlock() maybeKill() // check if the app is down start = true }() for e := range reg.Events { log.Info("got health monitor event", "status", e.Status) mtx.Lock() lastStatus = e.Status if !start { mtx.Unlock() continue } maybeKill() mtx.Unlock() } }() } return reg.Register(), nil }