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) }
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, } }
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:]...) } } } } }
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 }
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 }
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) }
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 }
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)) }
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)) }
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) }
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 }
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 }
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)) } }
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]) } }
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) }
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) } }
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] } } }
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) }
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) }