func DeleteRoute(route core.Route) error { // in case of failure oldRoutes, err := database.GetRoutes() if err != nil { return err } // apply to proxymgr err = proxymgr.DeleteRoute(route) if err != nil { return err } if !database.CentralStore { // save to backend err = database.DeleteRoute(route) if err != nil { // undo proxymgr action if uerr := proxymgr.SetRoutes(oldRoutes); uerr != nil { err = fmt.Errorf("%v - %v", err.Error(), uerr.Error()) } return err } } return nil }
func TestNoneDeleteRoute(t *testing.T) { if err := cluster.DeleteRoute(testRoute); err != nil { t.Errorf("Failed to DELETE route - %v", err) t.FailNow() } // don't use cluster.GetRoutes() routes, err := database.GetRoutes() if len(routes) != 0 { t.Error("Failed to DELETE route - %v", err) } }
func TestDeleteRoute(t *testing.T) { if err := database.DeleteRoute(testRoute); err != nil { t.Errorf("Failed to DELETE route - %v", err) } routes, err := database.GetRoutes() if err != nil { t.Error(err) } if len(routes) != 0 { t.Errorf("Failed to delete route") } }
//////////////////////////////////////////////////////////////////////////////// // ROUTES //////////////////////////////////////////////////////////////////////////////// func TestNoneSetRoute(t *testing.T) { if err := cluster.SetRoute(testRoute); err != nil { t.Errorf("Failed to SET route - %v", err) t.FailNow() } routes, err := database.GetRoutes() if err != nil { t.Error(err) } if len(routes) != 1 || routes[0].Domain != testRoute.Domain { t.Errorf("Read route differs from written route") } }
func TestSetRoutes(t *testing.T) { routes := []core.Route{testRoute} if err := database.SetRoutes(routes); err != nil { t.Errorf("Failed to SET routes - %v", err) } routes, err := database.GetRoutes() if err != nil { t.Error(err) } if len(routes) != 1 { t.Errorf("Wrong number of routes") } }
func TestNoneSetRoutes(t *testing.T) { routes := []core.Route{testRoute} if err := cluster.SetRoutes(routes); err != nil { t.Errorf("Failed to SET routes - %v", err) t.FailNow() } // don't use cluster.GetRoutes() routes, err := database.GetRoutes() if err != nil { t.Error(err) } if len(routes) != 1 || routes[0].Domain != testRoute.Domain { t.Errorf("Read route differs from written route") } }
// GetRoutes gets a list of routes from the database, or another cluster member. func (r *Redis) GetRoutes() ([]core.Route, error) { if database.CentralStore { return database.GetRoutes() } conn := pool.Get() defer conn.Close() // get known members(other than me) to 'poll' for routes members, _ := redis.Strings(conn.Do("SMEMBERS", "members")) if len(members) == 0 { // should only happen on new cluster // assume i'm ok to be master so don't reset imported routes config.Log.Trace("[cluster] - Assuming OK to be master, using routes from my database...") return common.GetRoutes() } for i := range members { if members[i] == self { // if i'm in the list of members, new requests should have failed while `waitForMembers`ing config.Log.Trace("[cluster] - Assuming I was in sync, using routes from my database...") return common.GetRoutes() } } c, err := redis.DialURL(config.ClusterConnection, redis.DialConnectTimeout(15*time.Second), redis.DialPassword(config.ClusterToken)) if err != nil { return nil, fmt.Errorf("Failed to reach redis for routes subscriber - %v", err) } defer c.Close() message := make(chan interface{}) subconn := redis.PubSubConn{c} // subscribe to channel that routes will be published on if err := subconn.Subscribe("routes"); err != nil { return nil, fmt.Errorf("Failed to reach redis for routes subscriber - %v", err) } defer subconn.Close() // listen always go func() { for { message <- subconn.Receive() } }() // todo: maybe use ttl? // timeout is how long to wait for the listed members to come back online timeout := time.After(time.Duration(20) * time.Second) // loop attempts for timeout, allows last dead members to start back up for { select { case <-timeout: return nil, fmt.Errorf("Timed out waiting for routes from %v", strings.Join(members, ", ")) default: // request routes from each member until successful for _, member := range members { // memberTimeout is how long to wait for a member to respond with list of routes memberTimeout := time.After(3 * time.Second) // ask a member for its routes config.Log.Trace("[cluster] - Attempting to request routes from %v...", member) _, err := conn.Do("PUBLISH", "portal", fmt.Sprintf("get-routes %s", member)) if err != nil { return nil, err } // wait for member to respond for { select { case <-memberTimeout: config.Log.Debug("[cluster] - Timed out waiting for routes from %v", member) goto nextRouteMember case msg := <-message: switch v := msg.(type) { case redis.Message: config.Log.Trace("[cluster] - Received message on 'routes' channel") var routes []core.Route err = parseBody(v.Data, &routes) if err != nil { return nil, fmt.Errorf("Failed to marshal routes - %v", err.Error()) } config.Log.Trace("[cluster] - Routes from cluster: %#v\n", routes) return routes, nil case error: return nil, fmt.Errorf("Subscriber failed to receive routes - %v", v.Error()) } } } nextRouteMember: } } } }
func GetRoutes() ([]core.Route, error) { return database.GetRoutes() }