func (c *Config) ConstructRule(rule Rule) *routing.Rule {
	if rule.Next == "" && rule.Pool == "" {
		logger.Errorf("[rule %s] no pool or trie", rule.Name)
		return routing.DummyRule(rule.Name)
	}

	var next *routing.Trie
	if rule.Next != "" {
		next = c.Tries[rule.Next]
		if next == nil {
			logger.Errorf("[rule %s] trie %s absent", rule.Name, rule.Next)
			next = routing.DummyTrie(rule.Next)
		}
	}

	var pool *backend.Pool
	if rule.Pool != "" {
		pool = c.Pools[rule.Pool]
		if pool == nil {
			logger.Errorf("[rule %s] trie %s absent", rule.Name, rule.Pool)
			pool = backend.DummyPool(rule.Pool)
		}
	}

	matcher, err := c.MatcherFactory.Make(rule.Type, rule.Value)
	if err != nil {
		logger.Errorf("[rule %s] setting matcher false", rule.Name)
		matcher = routing.NewStaticMatcher("false")
	}

	return routing.NewRule(rule.Name, matcher, next, pool)
}
Exemple #2
0
func (s *Server) CheckStatus(tout time.Duration) {
	r, _ := http.NewRequest("GET", "http://"+s.Address+"/healthz", nil)

	resErrCh := make(chan ResponseError)
	go s.RoundTrip(r, resErrCh)

	select {
	case resErr := <-resErrCh:
		if resErr.Error == nil {
			defer resErr.Response.Body.Close()

			//if status has changed then log
			if s.Status.ParseAndSet(resErr.Response) {
				logger.Printf("[server %s] status code changed to %d\n", s.Address, resErr.Response.StatusCode)
			}
		} else {
			//if status has changed then log
			if s.Status.Set(StatusCritical) {
				logger.Errorf("[server %s] status set to critical! : %s\n", s.Address, resErr.Error)
			}
		}
	case <-time.After(tout):
		s.Transport.CancelRequest(r)
		if s.Status.Set(StatusCritical) {
			logger.Errorf("[server %s] status set to critical due to timeout!\n", s.Address)
		}
	}
}
func (c *Config) ConstructPoolConfig(pool Pool) backend.PoolConfig {
	name, config := pool.Name, pool.Config

	healthzEvery, err := time.ParseDuration(config.HealthzEvery)
	if err != nil {
		logger.Errorf("[config %s] %s is not valid duration", name, config.HealthzEvery)
		healthzEvery = defaultHealthzEvery
	}

	healthzTimeout, err := time.ParseDuration(config.HealthzTimeout)
	if err != nil {
		logger.Errorf("[config %s] %s is not valid duration", name, config.HealthzTimeout)
		healthzTimeout = defaultHealthzTimeout
	}

	requestTimeout, err := time.ParseDuration(config.RequestTimeout)
	if err != nil {
		logger.Errorf("[config %s] %s is not valid duration", name, config.RequestTimeout)
		requestTimeout = defaultRequestTimeout
	}

	status := config.Status
	if !backend.IsValidStatus(status) {
		logger.Errorf("[config %s] %s is not valid status", name, config.Status)
		status = "OK"
	}

	return backend.PoolConfig{
		HealthzEvery:   healthzEvery,
		HealthzTimeout: healthzTimeout,
		RequestTimeout: requestTimeout,
		Status:         status,
	}
}
Exemple #4
0
func (z *ZkConn) ManageTree(node string, callbacks ...EventCallbacks) {
	if len(callbacks) == 0 {
		return
	}

	children, _, eventCh, err := z.Conn.ChildrenW(node)
	if err != nil {
		logger.Errorf("[zkconn %d] ChildrenW(%s): %s", z, node, err)
		return
	}

	for _, child := range children {
		childNode := path.Join(node, child)
		z.ManageNode(childNode, callbacks[0])
		if len(callbacks) > 1 {
			go z.ManageTree(childNode, callbacks[1:]...)
		}
	}

	for {
		ev := <-eventCh

		if ev.State == zookeeper.STATE_CLOSED {
			// shutdown was called on ZkConn?
			return
		}

		if ev.State == zookeeper.STATE_EXPIRED_SESSION ||
			ev.State == zookeeper.STATE_CONNECTING {
			logger.Printf("[zkconn %d] connection lost, stop watching %s", z, node)
			return
		}

		switch ev.Type {
		case zookeeper.EVENT_DELETED:
			logger.Printf("[zkconn %d] node deleted, stop watching %s", z, node)
			return
		case zookeeper.EVENT_CHILD:
			prev := children
			children, _, eventCh, err = z.Conn.ChildrenW(node)
			if err != nil {
				logger.Errorf("[zkconn %d] ChildrenW(%s): %s", z, node, err)
				return
			}
			for _, child := range ArrayDiff(children, prev) {
				childNode := path.Join(node, child)
				z.ManageNode(childNode, callbacks[0])
				if len(callbacks) > 1 {
					go z.ManageTree(childNode, callbacks[1:]...)
				}
			}
		}
	}
}
Exemple #5
0
func (p *Pool) AddServer(name string, server *Server) {
	if _, ok := p.Servers[name]; ok {
		logger.Errorf("[pool %s] server %s exists", p.Name, name)
		return
	}
	p.Servers[name] = server
}
Exemple #6
0
func (c *Config) AddPort(port Port) {
	c.Lock()
	defer c.Unlock()

	if _, ok := c.Ports[port.Port]; ok {
		logger.Errorf("port %s exists in config", port.Port)
		return
	}

	trie, ok := c.Tries[port.Trie]
	if !ok {
		trie = routing.DummyTrie(port.Trie)
		logger.Errorf("no trie %s in config", port.Trie)
	}
	c.Ports[port.Port] = trie
}
Exemple #7
0
func (c *Config) DelTrie(name string) {
	c.Lock()
	defer c.Unlock()

	if _, ok := c.Tries[name]; !ok {
		logger.Errorf("no trie %s to delete", name)
		return
	}

	// nil references to this trie
	dummy := routing.DummyTrie(name)
	for _, rule := range c.Rules {
		if rule.Next == name {
			rule.NextPtr = dummy
		}
	}

	for num, _ := range c.Ports {
		if c.Ports[num].Name == name {
			c.Ports[num] = dummy
		}
	}

	delete(c.Tries, name)
}
Exemple #8
0
func (c *Config) StatusZJSON() (string, error) {
	var response []StatusZ

	c.RLock()
	for _, pool := range c.Pools {
		for _, server := range pool.Servers {
			s := StatusZ{
				Pool:             pool.Name,
				Server:           server.Address,
				RequestsInFlight: server.Metrics.RequestsInFlight,
				RequestsServiced: server.Metrics.RequestsServiced,
				Status:           server.Status.Current,
				StatusChanged:    fmt.Sprintf("%s", server.Status.Changed),
			}
			response = append(response, s)
		}
	}
	defer c.RUnlock()

	data, err := json.Marshal(response)
	if err != nil {
		logger.Errorf("[statusz json] %s", err)
		return "", err
	}

	return string(data), nil
}
Exemple #9
0
func (p *Pool) DelServer(name string) {
	if _, ok := p.Servers[name]; !ok {
		logger.Errorf("[pool %s] server %s absent", p.Name, name)
		return
	}

	delete(p.Servers, name)
}
func (p *PortCallbacks) Changed(zkPath, jsonBlob string) {
	logger.Debugf("PortCallbacks.Changed(%s)", zkPath, jsonBlob)
	var port config.Port
	if err := json.Unmarshal([]byte(jsonBlob), &port); err != nil {
		logger.Errorf("%s unmarshalling %s as port", err.Error(), jsonBlob)
		return
	}
	p.config.UpdatePort(port)
}
func (p *PoolCallbacks) Created(zkPath, jsonBlob string) {
	logger.Debugf("PoolCallbacks.Created(%s, %s)", zkPath, jsonBlob)
	var zkPool zk.ZkPool
	if err := json.Unmarshal([]byte(jsonBlob), &zkPool); err != nil {
		logger.Errorf("%s unmarshalling %s as pool", err.Error(), jsonBlob)
		return
	}
	p.config.AddPool(zkPool.Pool(map[string]config.Host{}))
}
func (p *PoolCallbacks) Changed(path, jsonBlob string) {
	logger.Debugf("PoolCallbacks.Changed(%s, %s)", path, jsonBlob)
	var zkPool zk.ZkPool
	if err := json.Unmarshal([]byte(jsonBlob), &zkPool); err != nil {
		logger.Errorf("%s unmarshalling %s as pool", err.Error(), jsonBlob)
		return
	}
	p.config.UpdatePool(zkPool.Pool(nil))
}
func (p *RuleCallbacks) Created(zkPath, jsonBlob string) {
	logger.Debugf("RuleCallbacks.Created(%s, %s)", zkPath, jsonBlob)
	var rule config.Rule
	if err := json.Unmarshal([]byte(jsonBlob), &rule); err != nil {
		logger.Errorf("%s unmarshalling %s as rule", err.Error(), jsonBlob)
		return
	}
	p.config.AddRule(rule)
}
func (p *TrieCallbacks) Changed(path, jsonBlob string) {
	logger.Debugf("TrieCallbacks.Changed(%s, %s)", path, jsonBlob)
	var trie config.Trie
	if err := json.Unmarshal([]byte(jsonBlob), &trie); err != nil {
		logger.Errorf("%s unmarshalling %s as trie", err.Error(), jsonBlob)
		return
	}
	p.config.UpdateTrie(trie)
}
func (p *TrieCallbacks) Created(zkPath, jsonBlob string) {
	logger.Debugf("TrieCallbacks.Created(%s, %s)", zkPath, jsonBlob)
	var trie config.Trie
	err := json.Unmarshal([]byte(jsonBlob), &trie)
	if err != nil {
		logger.Errorf("%s unmarshalling %s as trie", err.Error(), jsonBlob)
		return
	}
	p.config.AddTrie(trie)
}
func (p *PortCallbacks) Deleted(zkPath string) {
	logger.Debugf("PortCallbacks.Deleted(%s)", zkPath)
	port, err := strconv.ParseUint(path.Base(zkPath), 10, 16)
	if err != nil {
		logger.Errorf("%s interpreting base of %s as uint16", err.Error(), zkPath)
		return
	}
	p.config.DelPort(uint16(port))
	p.router.DelPort(uint16(port))
}
Exemple #17
0
func (c *Config) UpdatePool(pool Pool) {
	c.Lock()
	defer c.Unlock()

	if _, ok := c.Pools[pool.Name]; !ok {
		logger.Errorf("no pool %s to update", pool.Name)
		return
	}

	c.Pools[pool.Name].Reconfigure(c.ConstructPoolConfig(pool))
}
Exemple #18
0
func (c *Config) DelPort(num uint16) {
	c.Lock()
	defer c.Unlock()

	if _, ok := c.Ports[num]; !ok {
		logger.Errorf("no port %u to delete", num)
		return
	}

	delete(c.Ports, num)
}
Exemple #19
0
func (c *Config) UpdatePort(port Port) {
	c.Lock()
	defer c.Unlock()

	trie, ok := c.Tries[port.Trie]
	if !ok {
		trie = routing.DummyTrie(port.Trie)
		logger.Errorf("no trie %s in config", port.Trie)
	}
	c.Ports[port.Port] = trie
}
Exemple #20
0
func (z *ZkConn) ManageNode(node string, callbacks EventCallbacks) error {
	content, _, eventCh, err := z.Conn.GetW(node)
	if err != nil {
		logger.Errorf("[zkconn %d] GetW(%s): %s", z, node, err)
		return err
	}

	callbacks.Created(node, content)

	go func() {
		for {
			ev := <-eventCh

			if ev.State == zookeeper.STATE_CLOSED {
				// shutdown was called on ZkConn?
				return
			}

			if ev.State == zookeeper.STATE_EXPIRED_SESSION ||
				ev.State == zookeeper.STATE_CONNECTING {
				logger.Printf("[zkconn %d] connection lost, stop watching %s", z, node)
				return
			}

			switch ev.Type {
			case zookeeper.EVENT_DELETED:
				callbacks.Deleted(node)
				return
			case zookeeper.EVENT_CHANGED:
				content, _, eventCh, err = z.Conn.GetW(node)
				if err != nil {
					logger.Errorf("[zkconn %d] GetW(%s): %s", z, node, err)
					return
				}
				callbacks.Changed(node, content)
			}
		}
	}()

	return nil
}
Exemple #21
0
func (s *Server) Handle(logRecord *logger.HAProxyLogRecord, tout time.Duration) {
	sTime := time.Now()
	s.Metrics.RequestStart()
	defer s.Metrics.RequestDone()

	// X-Forwarded-For; we are a proxy.
	ip := strings.Split(logRecord.Request.RemoteAddr, ":")[0]
	logRecord.Request.Header.Add("X-Forwarded-For", ip)
	logRecord.ServerUpdateRecord(s.Address, s.Metrics.RequestsServiced, s.Metrics.Cost(), sTime)
	resErrCh := make(chan ResponseError)
	tstart := time.Now()
	go s.RoundTrip(logRecord.Request, resErrCh)
	tend := time.Now()
	logRecord.UpdateTr(tstart, tend)
	select {
	case resErr := <-resErrCh:
		if resErr.Error == nil {
			defer resErr.Response.Body.Close()

			logRecord.CopyHeaders(resErr.Response.Header)
			logRecord.WriteHeader(resErr.Response.StatusCode)

			err := logRecord.Copy(resErr.Response.Body)
			if err != nil {
				logger.Errorf("[server %s] failed attempting to copy response body: %s\n", s.Address, err)
			} else {
				logRecord.Log()
			}
		} else {
			logger.Errorf("[server %s] failed attempting the roundtrip: %s\n", s.Address, resErr.Error)
			logRecord.Error(logger.BadGatewayMsg, http.StatusBadGateway)
			logRecord.Terminate("Server: " + logger.BadGatewayMsg)
		}
	case <-time.After(tout):
		s.Transport.CancelRequest(logRecord.Request)
		logger.Printf("[server %s] round trip timed out!", s.Address)
		logRecord.Error(logger.GatewayTimeoutMsg, http.StatusGatewayTimeout)
		logRecord.Terminate("Server: " + logger.GatewayTimeoutMsg)
	}
}
func (c *Config) ConstructTrie(trie Trie) *routing.Trie {
	list := []*routing.Rule{}

	for _, rule := range trie.Rules {
		if _, ok := c.Rules[rule]; ok {
			list = append(list, c.Rules[rule])
		} else {
			logger.Errorf("[trie %s] rule %s absent", trie.Name, rule)
			list = append(list, routing.DummyRule(rule))
		}
	}

	return routing.NewTrie(trie.Name, list)
}
func (h *HostCallbacks) Created(zkPath, jsonBlob string) {
	logger.Debugf("HostCallbacks.Created(%s, %s)", zkPath, jsonBlob)
	hostName, poolName := h.splitPath(zkPath)

	var host config.Host
	if err := json.Unmarshal([]byte(jsonBlob), &host); err != nil {
		logger.Errorf("%s unmarshalling %s as host", err.Error(), jsonBlob)
		return
	}

	if pool := h.config.Pools[poolName]; pool != nil {
		pool.AddServer(hostName, h.config.ConstructServer(host))
	}
}
Exemple #24
0
func (c *Config) AddRule(rule Rule) {
	c.Lock()
	defer c.Unlock()

	if _, ok := c.Rules[rule.Name]; ok {
		logger.Errorf("rule %s exists in config", rule.Name)
		return
	}

	c.Rules[rule.Name] = c.ConstructRule(rule)

	// update references to this rule
	for _, trie := range c.Tries {
		trie.UpdateRule(c.Rules[rule.Name])
	}
}
Exemple #25
0
func (c *Config) DelRule(name string) {
	c.Lock()
	defer c.Unlock()

	if _, ok := c.Rules[name]; !ok {
		logger.Errorf("no rule %s to delete", name)
		return
	}

	// nil references to this rule
	dummy := routing.DummyRule(name)
	for _, trie := range c.Tries {
		trie.UpdateRule(dummy)
	}

	delete(c.Rules, name)
}
Exemple #26
0
func (s *StatusServer) Run(port uint16, tout time.Duration) {
	gmux := mux.NewRouter()
	gmux.HandleFunc("/statusz", s.StatusZ).Methods("GET")
	gmux.HandleFunc("/statusz.json", s.StatusZJSON).Methods("GET")
	gmux.PathPrefix("/{port:[0-9]+}").HandlerFunc(s.PrintRouting)

	server := http.Server{
		Handler:      gmux,
		Addr:         fmt.Sprintf("0.0.0.0:%d", port),
		ReadTimeout:  tout,
		WriteTimeout: tout,
	}

	for {
		logger.Errorf("[status server] %s", server.ListenAndServe())
		time.Sleep(1 * time.Second)
	}
}
Exemple #27
0
func (c *Config) AddPool(pool Pool) {
	c.Lock()
	defer c.Unlock()

	if _, ok := c.Pools[pool.Name]; ok {
		logger.Errorf("pool exists in config", pool.Name)
		return
	}

	c.Pools[pool.Name] = c.ConstructPool(pool)

	// update references to this pool
	for _, rule := range c.Rules {
		if rule.Pool == pool.Name {
			rule.PoolPtr = c.Pools[pool.Name]
		}
	}
}
Exemple #28
0
func (c *Config) DelPool(name string) {
	c.Lock()
	defer c.Unlock()

	if _, ok := c.Pools[name]; !ok {
		logger.Errorf("no pool %s to delete", name)
		return
	}

	// nil references to this pool
	for _, rule := range c.Rules {
		if rule.Pool == name {
			rule.PoolPtr = nil
		}
	}

	c.Pools[name].Shutdown()
	delete(c.Pools, name)
}
Exemple #29
0
func (c *Config) AddTrie(trie Trie) {
	c.Lock()
	defer c.Unlock()

	if _, ok := c.Tries[trie.Name]; ok {
		logger.Errorf("trie %s exists in config", trie.Name)
		return
	}

	c.Tries[trie.Name] = c.ConstructTrie(trie)

	// update references to this trie
	for _, rule := range c.Rules {
		if rule.Next == trie.Name {
			rule.NextPtr = c.Tries[trie.Name]
		}
	}

	for num, _ := range c.Ports {
		if c.Ports[num].Name == trie.Name {
			c.Ports[num] = c.Tries[trie.Name]
		}
	}
}
func (h *HostCallbacks) Changed(path, jsonBlob string) {
	logger.Errorf("HostCallbacks.Changed(%s, %s)", path, jsonBlob)
}