作者:shantano
项目:atlantis-route
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)
}
作者:shantano
项目:atlantis-route
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)
}
}
}
作者:shantano
项目:atlantis-route
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,
}
}
作者:shantano
项目:atlantis-route
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:]...)
}
}
}
}
}
作者:shantano
项目:atlantis-route
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
}
作者:shantano
项目:atlantis-route
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
}
作者:shantano
项目:atlantis-route
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)
}
作者:shantano
项目:atlantis-route
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
}
作者:shantano
项目:atlantis-route
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)
}
作者:shantano
项目:atlantis-route
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)
}
作者:shantano
项目:atlantis-route
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{}))
}
作者:shantano
项目:atlantis-route
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))
}
作者:shantano
项目:atlantis-route
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))
}
作者:shantano
项目:atlantis-route
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)
}
作者:shantano
项目:atlantis-route
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
}
作者:shantano
项目:atlantis-route
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
}
作者:shantano
项目:atlantis-route
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)
}
}
作者:shantano
项目:atlantis-route
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)
}
作者:shantano
项目:atlantis-route
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])
}
}
作者:shantano
项目:atlantis-route
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)
}