mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-31 07:20:13 +00:00
Fix a bug where nodes that weren't schedulable or ready are added to load balancers
This commit is contained in:
parent
88008de96b
commit
604203595a
@ -581,13 +581,40 @@ func stringSlicesEqual(x, y []string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func hostsFromNodeList(list *api.NodeList) []string {
|
func hostsFromNodeList(list *api.NodeList) []string {
|
||||||
result := make([]string, len(list.Items))
|
result := []string{}
|
||||||
for ix := range list.Items {
|
for ix := range list.Items {
|
||||||
result[ix] = list.Items[ix].Name
|
if list.Items[ix].Spec.Unschedulable {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, list.Items[ix].Name)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getNodeConditionPredicate() cache.NodeConditionPredicate {
|
||||||
|
return func(node api.Node) bool {
|
||||||
|
// We add the master to the node list, but its unschedulable. So we use this to filter
|
||||||
|
// the master.
|
||||||
|
// TODO: Use a node annotation to indicate the master
|
||||||
|
if node.Spec.Unschedulable {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// If we have no info, don't accept
|
||||||
|
if len(node.Status.Conditions) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, cond := range node.Status.Conditions {
|
||||||
|
// We consider the node for load balancing only when its NodeReady condition status
|
||||||
|
// is ConditionTrue
|
||||||
|
if cond.Type == api.NodeReady && cond.Status != api.ConditionTrue {
|
||||||
|
glog.V(4).Infof("Ignoring node %v with %v condition status %v", node.Name, cond.Type, cond.Status)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// nodeSyncLoop handles updating the hosts pointed to by all load
|
// nodeSyncLoop handles updating the hosts pointed to by all load
|
||||||
// balancers whenever the set of nodes in the cluster changes.
|
// balancers whenever the set of nodes in the cluster changes.
|
||||||
func (s *ServiceController) nodeSyncLoop(period time.Duration) {
|
func (s *ServiceController) nodeSyncLoop(period time.Duration) {
|
||||||
@ -598,7 +625,7 @@ func (s *ServiceController) nodeSyncLoop(period time.Duration) {
|
|||||||
// something to compile, and gofmt1.4 complains about using `_ = range`.
|
// something to compile, and gofmt1.4 complains about using `_ = range`.
|
||||||
for now := range time.Tick(period) {
|
for now := range time.Tick(period) {
|
||||||
_ = now
|
_ = now
|
||||||
nodes, err := s.nodeLister.List()
|
nodes, err := s.nodeLister.NodeCondition(getNodeConditionPredicate()).List()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Failed to retrieve current set of nodes from node lister: %v", err)
|
glog.Errorf("Failed to retrieve current set of nodes from node lister: %v", err)
|
||||||
continue
|
continue
|
||||||
|
@ -228,4 +228,102 @@ func TestUpdateNodesInExternalLoadBalancer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHostsFromNodeList(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
nodes *api.NodeList
|
||||||
|
expectedHosts []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
nodes: &api.NodeList{},
|
||||||
|
expectedHosts: []string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nodes: &api.NodeList{
|
||||||
|
Items: []api.Node{
|
||||||
|
{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||||
|
Status: api.NodeStatus{Phase: api.NodeRunning},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "bar"},
|
||||||
|
Status: api.NodeStatus{Phase: api.NodeRunning},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedHosts: []string{"foo", "bar"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nodes: &api.NodeList{
|
||||||
|
Items: []api.Node{
|
||||||
|
{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||||
|
Status: api.NodeStatus{Phase: api.NodeRunning},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "bar"},
|
||||||
|
Status: api.NodeStatus{Phase: api.NodeRunning},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "unschedulable"},
|
||||||
|
Spec: api.NodeSpec{Unschedulable: true},
|
||||||
|
Status: api.NodeStatus{Phase: api.NodeRunning},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedHosts: []string{"foo", "bar"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
hosts := hostsFromNodeList(test.nodes)
|
||||||
|
if !reflect.DeepEqual(hosts, test.expectedHosts) {
|
||||||
|
t.Errorf("expected: %v, saw: %v", test.expectedHosts, hosts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetNodeConditionPredicate(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
node api.Node
|
||||||
|
expectAccept bool
|
||||||
|
name string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
node: api.Node{},
|
||||||
|
expectAccept: false,
|
||||||
|
name: "empty",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: api.Node{
|
||||||
|
Status: api.NodeStatus{
|
||||||
|
Conditions: []api.NodeCondition{
|
||||||
|
{Type: api.NodeReady, Status: api.ConditionTrue},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectAccept: true,
|
||||||
|
name: "basic",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: api.Node{
|
||||||
|
Spec: api.NodeSpec{Unschedulable: true},
|
||||||
|
Status: api.NodeStatus{
|
||||||
|
Conditions: []api.NodeCondition{
|
||||||
|
{Type: api.NodeReady, Status: api.ConditionTrue},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectAccept: false,
|
||||||
|
name: "unschedulable",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
pred := getNodeConditionPredicate()
|
||||||
|
for _, test := range tests {
|
||||||
|
accept := pred(test.node)
|
||||||
|
if accept != test.expectAccept {
|
||||||
|
t.Errorf("Test failed for %s, expected %v, saw %v", test.name, test.expectAccept, accept)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(a-robinson): Add tests for update/sync/delete.
|
// TODO(a-robinson): Add tests for update/sync/delete.
|
||||||
|
Loading…
Reference in New Issue
Block a user