diff --git a/pkg/api/v1beta1/conversion.go b/pkg/api/v1beta1/conversion.go index 00abab8fbd..257f3e352f 100644 --- a/pkg/api/v1beta1/conversion.go +++ b/pkg/api/v1beta1/conversion.go @@ -1579,6 +1579,8 @@ func init() { switch label { case "name": return "metadata.name", value, nil + case "unschedulable": + return "spec.unschedulable", value, nil default: return "", "", fmt.Errorf("field label not supported: %s", label) } diff --git a/pkg/api/v1beta2/conversion.go b/pkg/api/v1beta2/conversion.go index d29c33904b..f2f5815d45 100644 --- a/pkg/api/v1beta2/conversion.go +++ b/pkg/api/v1beta2/conversion.go @@ -1504,6 +1504,8 @@ func init() { switch label { case "name": return "metadata.name", value, nil + case "unschedulable": + return "spec.unschedulable", value, nil default: return "", "", fmt.Errorf("field label not supported: %s", label) } diff --git a/pkg/api/v1beta3/conversion.go b/pkg/api/v1beta3/conversion.go index 81182c3950..700bda3701 100644 --- a/pkg/api/v1beta3/conversion.go +++ b/pkg/api/v1beta3/conversion.go @@ -44,6 +44,8 @@ func init() { switch label { case "metadata.name": return label, value, nil + case "spec.unschedulable": + return label, value, nil default: return "", "", fmt.Errorf("field label not supported: %s", label) } diff --git a/pkg/client/request.go b/pkg/client/request.go index d87b44dab2..b10e5a650a 100644 --- a/pkg/client/request.go +++ b/pkg/client/request.go @@ -250,8 +250,9 @@ func (r *Request) RequestURI(uri string) *Request { const ( // A constant that clients can use to refer in a field selector to the object name field. // Will be automatically emitted as the correct name for the API version. - ObjectNameField = "metadata.name" - PodHost = "spec.host" + NodeUnschedulable = "spec.unschedulable" + ObjectNameField = "metadata.name" + PodHost = "spec.host" ) type clientFieldNameToAPIVersionFieldName map[string]string @@ -294,10 +295,12 @@ func (v versionToResourceToFieldMapping) filterField(apiVersion, resourceType, f var fieldMappings = versionToResourceToFieldMapping{ "v1beta1": resourceTypeToFieldMapping{ "nodes": clientFieldNameToAPIVersionFieldName{ - ObjectNameField: "name", + ObjectNameField: "name", + NodeUnschedulable: "unschedulable", }, "minions": clientFieldNameToAPIVersionFieldName{ - ObjectNameField: "name", + ObjectNameField: "name", + NodeUnschedulable: "unschedulable", }, "pods": clientFieldNameToAPIVersionFieldName{ PodHost: "DesiredState.Host", @@ -305,10 +308,12 @@ var fieldMappings = versionToResourceToFieldMapping{ }, "v1beta2": resourceTypeToFieldMapping{ "nodes": clientFieldNameToAPIVersionFieldName{ - ObjectNameField: "name", + ObjectNameField: "name", + NodeUnschedulable: "unschedulable", }, "minions": clientFieldNameToAPIVersionFieldName{ - ObjectNameField: "name", + ObjectNameField: "name", + NodeUnschedulable: "unschedulable", }, "pods": clientFieldNameToAPIVersionFieldName{ PodHost: "DesiredState.Host", @@ -316,10 +321,12 @@ var fieldMappings = versionToResourceToFieldMapping{ }, "v1beta3": resourceTypeToFieldMapping{ "nodes": clientFieldNameToAPIVersionFieldName{ - ObjectNameField: "metadata.name", + ObjectNameField: "metadata.name", + NodeUnschedulable: "spec.unschedulable", }, "minions": clientFieldNameToAPIVersionFieldName{ - ObjectNameField: "metadata.name", + ObjectNameField: "metadata.name", + NodeUnschedulable: "spec.unschedulable", }, "pods": clientFieldNameToAPIVersionFieldName{ PodHost: "spec.host", diff --git a/pkg/registry/minion/rest.go b/pkg/registry/minion/rest.go index 6cc5d08a74..1c4c013e48 100644 --- a/pkg/registry/minion/rest.go +++ b/pkg/registry/minion/rest.go @@ -107,7 +107,8 @@ type ResourceGetter interface { // NodeToSelectableFields returns a label set that represents the object. func NodeToSelectableFields(node *api.Node) fields.Set { return fields.Set{ - "metadata.name": node.Name, + "metadata.name": node.Name, + "spec.unschedulable": fmt.Sprint(node.Spec.Unschedulable), } } diff --git a/plugin/pkg/scheduler/factory/factory.go b/plugin/pkg/scheduler/factory/factory.go index 97a76fc04a..9b5e2d9af8 100644 --- a/plugin/pkg/scheduler/factory/factory.go +++ b/plugin/pkg/scheduler/factory/factory.go @@ -28,7 +28,6 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache" "github.com/GoogleCloudPlatform/kubernetes/pkg/controller/framework" "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" - "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" algorithm "github.com/GoogleCloudPlatform/kubernetes/pkg/scheduler" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/scheduler" @@ -230,40 +229,9 @@ func (factory *ConfigFactory) createAssignedPodLW() *cache.ListWatch { // createMinionLW returns a cache.ListWatch that gets all changes to minions. func (factory *ConfigFactory) createMinionLW() *cache.ListWatch { - return cache.NewListWatchFromClient(factory.Client, "nodes", api.NamespaceAll, parseSelectorOrDie("")) -} - -// Lists all minions and filter out unhealthy ones, then returns -// an enumerator for cache.Poller. -func (factory *ConfigFactory) pollMinions() (cache.Enumerator, error) { - allNodes, err := factory.Client.Nodes().List(labels.Everything(), fields.Everything()) - if err != nil { - return nil, err - } - nodes := &api.NodeList{ - TypeMeta: allNodes.TypeMeta, - ListMeta: allNodes.ListMeta, - } - for _, node := range allNodes.Items { - conditionMap := make(map[api.NodeConditionType]*api.NodeCondition) - for i := range node.Status.Conditions { - cond := node.Status.Conditions[i] - conditionMap[cond.Type] = &cond - } - if node.Spec.Unschedulable { - continue - } - if condition, ok := conditionMap[api.NodeReady]; ok { - if condition.Status == api.ConditionTrue { - nodes.Items = append(nodes.Items, node) - } - } else { - // If no condition is set, we get unknown node condition. In such cases, - // do not add the node. - glog.V(2).Infof("Minion %s is not available. Skipping", node.Name) - } - } - return &nodeEnumerator{nodes}, nil + // TODO: Filter out nodes that doesn't have NodeReady condition. + fields := fields.Set{client.NodeUnschedulable: "false"}.AsSelector() + return cache.NewListWatchFromClient(factory.Client, "nodes", api.NamespaceAll, fields) } // Returns a cache.ListWatch that gets all changes to services. diff --git a/plugin/pkg/scheduler/factory/factory_test.go b/plugin/pkg/scheduler/factory/factory_test.go index c9b1ba4ba6..9c08b489ae 100644 --- a/plugin/pkg/scheduler/factory/factory_test.go +++ b/plugin/pkg/scheduler/factory/factory_test.go @@ -131,168 +131,6 @@ func PriorityTwo(pod api.Pod, podLister algorithm.PodLister, minionLister algori return []algorithm.HostPriority{}, nil } -func TestPollMinions(t *testing.T) { - table := []struct { - minions []api.Node - expectedCount int - }{ - { - minions: []api.Node{ - { - ObjectMeta: api.ObjectMeta{Name: "foo"}, - Status: api.NodeStatus{ - Conditions: []api.NodeCondition{ - {Type: api.NodeReady, Status: api.ConditionTrue}, - }, - }, - }, - { - ObjectMeta: api.ObjectMeta{Name: "fiz"}, - Spec: api.NodeSpec{ - Unschedulable: false, - }, - }, - { - ObjectMeta: api.ObjectMeta{Name: "baz"}, - Status: api.NodeStatus{ - Conditions: []api.NodeCondition{ - {Type: api.NodeReady, Status: api.ConditionTrue}, - {Type: api.NodeReady, Status: api.ConditionTrue}, - }, - }, - }, - { - ObjectMeta: api.ObjectMeta{Name: "fuz"}, - Status: api.NodeStatus{ - Conditions: []api.NodeCondition{ - {Type: api.NodeReady, Status: api.ConditionTrue}, - }, - }, - Spec: api.NodeSpec{ - Unschedulable: false, - }, - }, - { - ObjectMeta: api.ObjectMeta{Name: "buz"}, - Status: api.NodeStatus{ - Conditions: []api.NodeCondition{ - {Type: api.NodeReady, Status: api.ConditionTrue}, - }, - }, - Spec: api.NodeSpec{ - Unschedulable: true, - }, - }, - { - ObjectMeta: api.ObjectMeta{Name: "foobar"}, - Status: api.NodeStatus{ - Conditions: []api.NodeCondition{ - {Type: api.NodeReady, Status: api.ConditionFalse}, - }, - }, - Spec: api.NodeSpec{ - Unschedulable: false, - }, - }, - }, - expectedCount: 3, - }, - { - minions: []api.Node{ - { - ObjectMeta: api.ObjectMeta{Name: "foo"}, - Status: api.NodeStatus{ - Conditions: []api.NodeCondition{ - {Type: api.NodeReady, Status: api.ConditionTrue}, - }, - }, - }, - { - ObjectMeta: api.ObjectMeta{Name: "bar"}, - Status: api.NodeStatus{ - Conditions: []api.NodeCondition{ - {Type: api.NodeReady, Status: api.ConditionFalse}, - }, - }, - }, - }, - expectedCount: 1, - }, - { - minions: []api.Node{ - { - ObjectMeta: api.ObjectMeta{Name: "foo"}, - Spec: api.NodeSpec{ - Unschedulable: false, - }, - }, - { - ObjectMeta: api.ObjectMeta{Name: "bar"}, - Spec: api.NodeSpec{ - Unschedulable: true, - }, - }, - }, - expectedCount: 0, - }, - { - minions: []api.Node{ - { - ObjectMeta: api.ObjectMeta{Name: "foo"}, - Status: api.NodeStatus{ - Conditions: []api.NodeCondition{ - {Type: api.NodeReady, Status: api.ConditionTrue}, - {Type: "invalidValue", Status: api.ConditionFalse}}, - }, - }, - }, - expectedCount: 1, - }, - { - minions: []api.Node{ - { - ObjectMeta: api.ObjectMeta{Name: "foo"}, - Status: api.NodeStatus{ - Conditions: []api.NodeCondition{}, - }, - }, - }, - expectedCount: 0, - }, - } - - for _, item := range table { - ml := &api.NodeList{Items: item.minions} - handler := util.FakeHandler{ - StatusCode: 200, - ResponseBody: runtime.EncodeOrDie(latest.Codec, ml), - T: t, - } - mux := http.NewServeMux() - // FakeHandler musn't be sent requests other than the one you want to test. - resource := "nodes" - if api.PreV1Beta3(testapi.Version()) { - resource = "minions" - } - mux.Handle(testapi.ResourcePath(resource, api.NamespaceAll, ""), &handler) - server := httptest.NewServer(mux) - defer server.Close() - client := client.NewOrDie(&client.Config{Host: server.URL, Version: testapi.Version()}) - cf := NewConfigFactory(client) - - ce, err := cf.pollMinions() - if err != nil { - t.Errorf("Unexpected error: %v", err) - continue - } - handler.ValidateRequest(t, testapi.ResourcePath(resource, api.NamespaceAll, ""), "GET", nil) - - if a := ce.Len(); item.expectedCount != a { - t.Errorf("Expected %v, got %v", item.expectedCount, a) - } - } -} - func TestDefaultErrorFunc(t *testing.T) { testPod := &api.Pod{ ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"},