Example #1
0
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")
}
Example #2
0
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)
	}
}
Example #3
0
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()
		},
	}
}
Example #4
0
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")
}
Example #5
0
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
}