Beispiel #1
1
func (r *fakeRouter) RemoveRoute(name string, address *url.URL) error {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	if !r.HasBackend(backendName) {
		return router.ErrBackendNotFound
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	if r.failuresByIp[address.String()] {
		return ErrForcedFailure
	}
	index := -1
	routes := r.backends[backendName]
	for i := range routes {
		if routes[i] == address.String() {
			index = i
			break
		}
	}
	if index < 0 {
		return router.ErrRouteNotFound
	}
	routes[index] = routes[len(routes)-1]
	r.backends[backendName] = routes[:len(routes)-1]
	return nil
}
Beispiel #2
0
func (s *ExternalSuite) TestSwap(c *check.C) {
	backend1 := "b1"
	backend2 := "b2"
	r, err := router.Get("fake")
	c.Assert(err, check.IsNil)
	r.AddBackend(backend1)
	addr1, _ := url.Parse("http://127.0.0.1")
	r.AddRoute(backend1, addr1)
	r.AddBackend(backend2)
	addr2, _ := url.Parse("http://10.10.10.10")
	r.AddRoute(backend2, addr2)
	err = router.Swap(r, backend1, backend2)
	c.Assert(err, check.IsNil)
	routes1, err := r.Routes(backend1)
	c.Assert(err, check.IsNil)
	c.Assert(routes1, check.DeepEquals, []*url.URL{addr1})
	routes2, err := r.Routes(backend2)
	c.Assert(err, check.IsNil)
	c.Assert(routes2, check.DeepEquals, []*url.URL{addr2})
	name1, err := router.Retrieve(backend1)
	c.Assert(err, check.IsNil)
	c.Assert(name1, check.Equals, backend2)
	name2, err := router.Retrieve(backend2)
	c.Assert(err, check.IsNil)
	c.Assert(name2, check.Equals, backend1)
}
Beispiel #3
0
func (s *RouterSuite) TestRemoveBackendKeepsInRouter(c *check.C) {
	_, err := router.Retrieve(testBackend1)
	c.Assert(err, check.Equals, router.ErrBackendNotFound)
	err = s.Router.AddBackend(testBackend1)
	c.Assert(err, check.IsNil)
	name, err := router.Retrieve(testBackend1)
	c.Assert(err, check.IsNil)
	c.Assert(name, check.Equals, testBackend1)
	err = s.Router.RemoveBackend(testBackend1)
	c.Assert(err, check.IsNil)
	name, err = router.Retrieve(testBackend1)
	c.Assert(err, check.IsNil)
	c.Assert(name, check.Equals, testBackend1)
}
Beispiel #4
0
func (s *ExternalSuite) TestSwapCnameOnly(c *check.C) {
	backend1 := "bx1"
	backend2 := "bx2"
	r, err := router.Get("fake")
	c.Assert(err, check.IsNil)
	cnameRouter, ok := r.(router.CNameRouter)
	c.Assert(ok, check.Equals, true)
	err = r.AddBackend(backend1)
	c.Assert(err, check.IsNil)
	addr1, err := url.Parse("http://127.0.0.1")
	c.Assert(err, check.IsNil)
	r.AddRoute(backend1, addr1)
	err = cnameRouter.SetCName("cname.com", backend1)
	c.Assert(err, check.IsNil)
	err = r.AddBackend(backend2)
	c.Assert(err, check.IsNil)
	addr2, err := url.Parse("http://10.10.10.10")
	c.Assert(err, check.IsNil)
	r.AddRoute(backend2, addr2)
	err = router.Swap(r, backend1, backend2, true)
	c.Assert(err, check.IsNil)
	routes1, err := r.Routes(backend1)
	c.Assert(err, check.IsNil)
	c.Assert(routes1, check.DeepEquals, []*url.URL{addr1})
	routes2, err := r.Routes(backend2)
	c.Assert(err, check.IsNil)
	c.Assert(routes2, check.DeepEquals, []*url.URL{addr2})
	name1, err := router.Retrieve(backend1)
	c.Assert(err, check.IsNil)
	c.Assert(name1, check.Equals, backend1)
	name2, err := router.Retrieve(backend2)
	c.Assert(err, check.IsNil)
	c.Assert(name2, check.Equals, backend2)
	cnames, err := cnameRouter.CNames(backend1)
	c.Assert(err, check.IsNil)
	c.Assert(cnames, check.HasLen, 0)
	expected := []*url.URL{{Host: "cname.com"}}
	cnames, err = cnameRouter.CNames(backend2)
	c.Assert(err, check.IsNil)
	c.Assert(expected, check.DeepEquals, cnames)
	err = router.Swap(r, backend1, backend2, true)
	c.Assert(err, check.IsNil)
	cnames, err = cnameRouter.CNames(backend1)
	c.Assert(err, check.IsNil)
	c.Assert(expected, check.DeepEquals, cnames)
	cnames, err = cnameRouter.CNames(backend2)
	c.Assert(err, check.IsNil)
	c.Assert(cnames, check.HasLen, 0)
}
Beispiel #5
0
func (r *fakeRouter) RemoveRoutes(name string, addresses []*url.URL) error {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	if !r.HasBackend(backendName) {
		return router.ErrBackendNotFound
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	for _, addr := range addresses {
		if r.failuresByIp[addr.Host] {
			return ErrForcedFailure
		}
	}
	routes := r.backends[backendName]
	for _, addr := range addresses {
		for i := range routes {
			if routes[i] == addr.Host {
				routes = append(routes[:i], routes[i+1:]...)
				break
			}
		}
	}
	r.backends[backendName] = routes
	return nil
}
Beispiel #6
0
func (s *S) TestRemoveBackend(c *check.C) {
	s.handler.RspCode = http.StatusNoContent
	err := router.Store("myapp", "myapp", routerName)
	c.Assert(err, check.IsNil)
	data := galebData{
		Name:          "myapp",
		BackendPoolId: s.server.URL + "/api/backend1",
		RootRuleId:    s.server.URL + "/api/rule1",
		VirtualHostId: s.server.URL + "/api/vh1",
		CNames: []galebCNameData{
			{CName: "my.1.cname", VirtualHostId: s.server.URL + "/api/vh2"},
			{CName: "my.2.cname", VirtualHostId: s.server.URL + "/api/vh3"},
		},
	}
	err = data.save()
	c.Assert(err, check.IsNil)
	gRouter, err := createRouter("routers:galeb")
	c.Assert(err, check.IsNil)
	err = gRouter.RemoveBackend("myapp")
	c.Assert(err, check.IsNil)
	c.Assert(s.handler.Url, check.DeepEquals, []string{
		"/api/vh1", "/api/vh2", "/api/vh3", "/api/rule1", "/api/backend1",
	})
	_, err = router.Retrieve("myapp")
	c.Assert(err, check.Equals, router.ErrBackendNotFound)
	_, err = getGalebData("myapp")
	c.Assert(err, check.ErrorMatches, "not found")
}
Beispiel #7
0
func (r *fakeRouter) RemoveRoute(name, ip string) error {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	if !r.HasBackend(backendName) {
		return ErrBackendNotFound
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	index := -1
	routes := r.backends[backendName]
	for i := range routes {
		if routes[i] == ip {
			index = i
			break
		}
	}
	if index < 0 {
		return errors.New("Route not found")
	}
	routes[index] = routes[len(routes)-1]
	r.backends[backendName] = routes[:len(routes)-1]
	return nil
}
Beispiel #8
0
func (r *galebRouter) SetCName(cname, name string) error {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	domain, err := config.GetString(r.prefix + ":domain")
	if err != nil {
		return err
	}
	if !router.ValidCName(cname, domain) {
		return router.ErrCNameNotAllowed
	}
	data, err := getGalebData(backendName)
	if err != nil {
		return err
	}
	client, err := r.getClient()
	if err != nil {
		return err
	}
	for _, val := range data.CNames {
		if val.CName == cname {
			return router.ErrCNameExists
		}
	}
	virtualHostParams := galebClient.VirtualHostParams{
		Name:        cname,
		RuleDefault: data.RootRuleId,
	}
	virtualHostId, err := client.AddVirtualHost(&virtualHostParams)
	if err != nil {
		return err
	}
	return data.addCName(cname, virtualHostId)
}
Beispiel #9
0
func (r *hipacheRouter) Routes(name string) ([]*url.URL, error) {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return nil, err
	}
	domain, err := config.GetString(r.prefix + ":domain")
	if err != nil {
		return nil, &router.RouterError{Op: "routes", Err: err}
	}
	frontend := "frontend:" + backendName + "." + domain
	conn := r.connect()
	defer conn.Close()
	routes, err := redis.Strings(conn.Do("LRANGE", frontend, 1, -1))
	if err != nil {
		return nil, &router.RouterError{Op: "routes", Err: err}
	}
	result := make([]*url.URL, len(routes))
	for i, route := range routes {
		result[i], err = url.Parse(route)
		if err != nil {
			return nil, err
		}
	}
	return result, nil
}
Beispiel #10
0
func (r *vulcandRouter) SetCName(cname, name string) error {
	usedName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	if !router.ValidCName(cname, r.domain) {
		return router.ErrCNameNotAllowed
	}
	frontendName := r.frontendName(cname)
	if found, _ := r.client.GetFrontend(engine.FrontendKey{Id: frontendName}); found != nil {
		return router.ErrCNameExists
	}
	frontend, err := engine.NewHTTPFrontend(
		frontendName,
		r.backendName(usedName),
		fmt.Sprintf(`Host(%q)`, cname),
		engine.HTTPFrontendSettings{},
	)
	if err != nil {
		return &router.RouterError{Err: err, Op: "set-cname"}
	}
	err = r.client.UpsertFrontend(*frontend, engine.NoTTL)
	if err != nil {
		return &router.RouterError{Err: err, Op: "set-cname"}
	}
	return nil
}
Beispiel #11
0
func (r *hipacheRouter) SetCName(cname, name string) error {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	domain, err := config.GetString(r.prefix + ":domain")
	if err != nil {
		return &routeError{"setCName", err}
	}
	if !r.validCName(cname) {
		err := errors.New(fmt.Sprintf("Invalid CNAME %s. You can't use tsuru's application domain.", cname))
		return &routeError{"setCName", err}
	}
	frontend := "frontend:" + backendName + "." + domain
	conn := r.connect()
	defer conn.Close()
	routes, err := redis.Strings(conn.Do("LRANGE", frontend, 0, -1))
	if err != nil {
		return &routeError{"get", err}
	}
	_, err = conn.Do("RPUSH", "cname:"+backendName, cname)
	if err != nil {
		return &routeError{"set", err}
	}
	frontend = "frontend:" + cname
	for _, r := range routes {
		_, err := conn.Do("RPUSH", frontend, r)
		if err != nil {
			return &routeError{"setCName", err}
		}
	}
	return nil
}
Beispiel #12
0
func (r *hipacheRouter) RemoveRoute(name string, address *url.URL) error {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	domain, err := config.GetString(r.prefix + ":domain")
	if err != nil {
		return &routeError{"remove", err}
	}
	frontend := "frontend:" + backendName + "." + domain
	if err := r.removeElement(frontend, address.String()); err != nil {
		return err
	}
	cnames, err := r.getCNames(backendName)
	if err != nil {
		return &routeError{"remove", err}
	}
	if cnames == nil {
		return nil
	}
	for _, cname := range cnames {
		err = r.removeElement("frontend:"+cname, address.String())
		if err != nil {
			return err
		}
	}
	return nil
}
Beispiel #13
0
func (r *hipacheRouter) AddRoute(name string, address *url.URL) error {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	domain, err := config.GetString(r.prefix + ":domain")
	if err != nil {
		log.Errorf("error on getting hipache domain in add route for %s - %s", backendName, address)
		return &routeError{"add", err}
	}
	frontend := "frontend:" + backendName + "." + domain
	if err := r.addRoute(frontend, address.String()); err != nil {
		log.Errorf("error on add route for %s - %s", backendName, address)
		return &routeError{"add", err}
	}
	cnames, err := r.getCNames(backendName)
	if err != nil {
		log.Errorf("error on get cname in add route for %s - %s", backendName, address)
		return err
	}
	if cnames == nil {
		return nil
	}
	for _, cname := range cnames {
		err = r.addRoute("frontend:"+cname, address.String())
		if err != nil {
			return err
		}
	}
	return nil
}
Beispiel #14
0
func (r *galebRouter) AddRoutes(name string, addresses []*url.URL) error {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	return r.client.AddBackends(addresses, r.poolName(backendName))
}
Beispiel #15
0
func (r *galebRouter) AddRoute(name string, address *url.URL) error {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	data, err := getGalebData(backendName)
	if err != nil {
		return err
	}
	for _, r := range data.Reals {
		if r.Real == address.Host {
			return router.ErrRouteExists
		}
	}
	client, err := r.getClient()
	if err != nil {
		return err
	}
	host, portStr, _ := net.SplitHostPort(address.Host)
	port, _ := strconv.Atoi(portStr)
	params := galebClient.BackendParams{
		Ip:          host,
		Port:        port,
		BackendPool: data.BackendPoolId,
	}
	backendId, err := client.AddBackend(&params)
	if err != nil {
		return err
	}
	return data.addReal(address.Host, backendId)
}
Beispiel #16
0
func (r *hipacheRouter) UnsetCName(cname, name string) error {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	conn := r.connect()
	defer conn.Close()
	currentCnames, err := redis.Strings(conn.Do("LRANGE", "cname:"+backendName, 0, -1))
	found := false
	for _, n := range currentCnames {
		if n == cname {
			found = true
			break
		}
	}
	if !found {
		return router.ErrCNameNotFound
	}
	_, err = conn.Do("LREM", "cname:"+backendName, 0, cname)
	if err != nil {
		return &router.RouterError{Op: "unsetCName", Err: err}
	}
	_, err = conn.Do("DEL", "frontend:"+cname)
	if err != nil {
		return &router.RouterError{Op: "unsetCName", Err: err}
	}
	return nil
}
Beispiel #17
0
func (r *galebRouter) RemoveRoutes(name string, addresses []*url.URL) error {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	addressMap := map[string]struct{}{}
	for _, addr := range addresses {
		addressMap[addr.Host] = struct{}{}
	}
	targets, err := r.client.FindTargetsByParent(r.poolName(backendName))
	if err != nil {
		return err
	}
	var ids []string
	for _, target := range targets {
		parsedAddr, err := url.Parse(target.Name)
		if err != nil {
			return err
		}
		if _, ok := addressMap[parsedAddr.Host]; ok {
			ids = append(ids, target.FullId())
		}
	}
	if len(ids) == 0 {
		return nil
	}
	return r.client.RemoveBackendsByIDs(ids)
}
Beispiel #18
0
func (r *galebRouter) Addr(name string) (string, error) {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return "", err
	}
	return r.virtualHostName(backendName), nil
}
Beispiel #19
0
func (r *fakeRouter) AddRoutes(name string, addresses []*url.URL) error {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	if !r.HasBackend(backendName) {
		return router.ErrBackendNotFound
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	for _, addr := range addresses {
		if r.failuresByIp[addr.String()] {
			return ErrForcedFailure
		}
	}
	routes := r.backends[backendName]
addresses:
	for _, addr := range addresses {
		for i := range routes {
			if routes[i] == addr.String() {
				continue addresses
			}
		}
		routes = append(routes, addr.String())
	}
	r.backends[backendName] = routes
	return nil
}
Beispiel #20
0
func (r *hipacheRouter) Routes(name string) ([]*url.URL, error) {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return nil, err
	}
	domain, err := config.GetString(r.prefix + ":domain")
	if err != nil {
		return nil, &router.RouterError{Op: "routes", Err: err}
	}
	frontend := "frontend:" + backendName + "." + domain
	conn, err := r.connect()
	if err != nil {
		return nil, &router.RouterError{Op: "routes", Err: err}
	}
	routes, err := conn.LRange(frontend, 0, -1).Result()
	if err != nil {
		return nil, &router.RouterError{Op: "routes", Err: err}
	}
	if len(routes) == 0 {
		return nil, router.ErrBackendNotFound
	}
	routes = routes[1:]
	result := make([]*url.URL, len(routes))
	for i, route := range routes {
		result[i], err = url.Parse(route)
		if err != nil {
			return nil, err
		}
	}
	return result, nil
}
Beispiel #21
0
func (r *hipacheRouter) UnsetCName(cname, name string) error {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	conn, err := r.connect()
	if err != nil {
		return &router.RouterError{Op: "unsetCName", Err: err}
	}
	currentCnames, err := conn.LRange("cname:"+backendName, 0, -1).Result()
	if err != nil {
		return &router.RouterError{Op: "unsetCName", Err: err}
	}
	found := false
	for _, n := range currentCnames {
		if n == cname {
			found = true
			break
		}
	}
	if !found {
		return router.ErrCNameNotFound
	}
	err = conn.LRem("cname:"+backendName, 0, cname).Err()
	if err != nil {
		return &router.RouterError{Op: "unsetCName", Err: err}
	}
	err = conn.Del("frontend:" + cname).Err()
	if err != nil {
		return &router.RouterError{Op: "unsetCName", Err: err}
	}
	return nil
}
Beispiel #22
0
func (r *hipacheRouter) RemoveRoutes(name string, addresses []*url.URL) error {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	domain, err := config.GetString(r.prefix + ":domain")
	if err != nil {
		return &router.RouterError{Op: "remove", Err: err}
	}
	toRemove := make([]string, len(addresses))
	for i := range addresses {
		addresses[i].Scheme = router.HttpScheme
		toRemove[i] = addresses[i].String()
	}
	frontend := "frontend:" + backendName + "." + domain
	err = r.removeElements(frontend, toRemove)
	if err != nil {
		return err
	}
	cnames, err := r.getCNames(backendName)
	if err != nil {
		return &router.RouterError{Op: "remove", Err: err}
	}
	if cnames == nil {
		return nil
	}
	for _, cname := range cnames {
		err = r.removeElements("frontend:"+cname, toRemove)
		if err != nil {
			return err
		}
	}
	return nil
}
Beispiel #23
0
func (r *hipacheRouter) RemoveRoute(name string, address *url.URL) error {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	domain, err := config.GetString(r.prefix + ":domain")
	if err != nil {
		return &router.RouterError{Op: "remove", Err: err}
	}
	frontend := "frontend:" + backendName + "." + domain
	address.Scheme = router.HttpScheme
	count, err := r.removeElement(frontend, address.String())
	if err != nil {
		return err
	}
	if count == 0 {
		return router.ErrRouteNotFound
	}
	cnames, err := r.getCNames(backendName)
	if err != nil {
		return &router.RouterError{Op: "remove", Err: err}
	}
	if cnames == nil {
		return nil
	}
	for _, cname := range cnames {
		_, err = r.removeElement("frontend:"+cname, address.String())
		if err != nil {
			return err
		}
	}
	return nil
}
Beispiel #24
0
func (r hipacheRouter) AddRoute(name, address string) error {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	domain, err := config.GetString("hipache:domain")
	if err != nil {
		log.Errorf("error on getting hipache domain in add route for %s - %s", backendName, address)
		return &routeError{"add", err}
	}
	frontend := "frontend:" + backendName + "." + domain
	if err := r.addRoute(frontend, address); err != nil {
		log.Errorf("error on add route for %s - %s", backendName, address)
		return &routeError{"add", err}
	}
	cname, err := r.getCName(backendName)
	if err != nil {
		log.Errorf("error on get cname in add route for %s - %s", backendName, address)
		return err
	}
	if cname == "" {
		return nil
	}
	return r.addRoute("frontend:"+cname, address)
}
Beispiel #25
0
func (r elbRouter) AddRoute(name, address string) error {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	_, err = r.elb().RegisterInstancesWithLoadBalancer([]string{address}, backendName)
	return err
}
Beispiel #26
0
func (s *S) TestSwap(c *gocheck.C) {
	instance1 := s.server.NewInstance()
	defer s.server.RemoveInstance(instance1)
	instance2 := s.server.NewInstance()
	defer s.server.RemoveInstance(instance2)
	backend1 := "b1"
	backend2 := "b2"
	elb := elbRouter{}
	err := elb.AddBackend(backend1)
	c.Assert(err, gocheck.IsNil)
	err = elb.AddRoute(backend1, instance1)
	c.Assert(err, gocheck.IsNil)
	err = elb.AddBackend(backend2)
	c.Assert(err, gocheck.IsNil)
	err = elb.AddRoute(backend2, instance2)
	c.Assert(err, gocheck.IsNil)
	retrieved1, err := router.Retrieve(backend1)
	c.Assert(err, gocheck.IsNil)
	c.Assert(retrieved1, gocheck.Equals, backend1)
	retrieved2, err := router.Retrieve(backend2)
	c.Assert(err, gocheck.IsNil)
	c.Assert(retrieved2, gocheck.Equals, backend2)
	err = elb.Swap(backend1, backend2)
	c.Assert(err, gocheck.IsNil)
	routes, err := elb.Routes(backend2)
	c.Assert(err, gocheck.IsNil)
	c.Assert(routes, gocheck.DeepEquals, []string{instance2})
	routes, err = elb.Routes(backend1)
	c.Assert(err, gocheck.IsNil)
	c.Assert(routes, gocheck.DeepEquals, []string{instance1})
	retrieved1, err = router.Retrieve(backend1)
	c.Assert(err, gocheck.IsNil)
	c.Assert(retrieved1, gocheck.Equals, backend2)
	retrieved2, err = router.Retrieve(backend2)
	c.Assert(err, gocheck.IsNil)
	c.Assert(retrieved2, gocheck.Equals, backend1)
	addr, err := elb.Addr(backend1)
	c.Assert(err, gocheck.IsNil)
	c.Assert(addr, gocheck.Equals, "b2-some-aws-stuff.us-east-1.elb.amazonaws.com")
	addr, err = elb.Addr(backend2)
	c.Assert(err, gocheck.IsNil)
	c.Assert(addr, gocheck.Equals, "b1-some-aws-stuff.us-east-1.elb.amazonaws.com")
}
Beispiel #27
0
func (r *fakeRouter) SetHealthcheck(name string, data router.HealthcheckData) error {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	r.healthcheck[backendName] = data
	return nil
}
Beispiel #28
0
func (r *fakeRouter) Routes(name string) ([]string, error) {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return nil, err
	}
	r.mutex.Lock()
	defer r.mutex.Unlock()
	routes := r.backends[backendName]
	return routes, nil
}
Beispiel #29
0
func (r *galebRouter) AddRoute(name string, address *url.URL) error {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	_, err = r.client.AddBackend(address, poolName(backendName))
	if err == galebClient.ErrItemAlreadyExists {
		return router.ErrRouteExists
	}
	return err
}
Beispiel #30
0
func (r elbRouter) RemoveBackend(name string) error {
	backendName, err := router.Retrieve(name)
	if err != nil {
		return err
	}
	_, err = r.elb().DeleteLoadBalancer(backendName)
	if err != nil {
		return err
	}
	return router.Remove(backendName)
}