From ed74197fde2d03ac8302f068351001b972a0f3d6 Mon Sep 17 00:00:00 2001 From: Eric Tune Date: Wed, 7 Jan 2015 15:33:17 -0800 Subject: [PATCH] Move Listers to pkg/client/cache. I would like to use these in kubelet and kube-proxy. This is the minimal change to get them moved. I will follow up with changes to make interfaces consistent and add Listers for other resources. --- pkg/client/cache/listers.go | 78 ++++++++++++++++++++ pkg/client/cache/listers_test.go | 76 +++++++++++++++++++ plugin/pkg/scheduler/factory/factory.go | 44 +---------- plugin/pkg/scheduler/factory/factory_test.go | 52 ------------- 4 files changed, 158 insertions(+), 92 deletions(-) create mode 100644 pkg/client/cache/listers.go create mode 100644 pkg/client/cache/listers_test.go diff --git a/pkg/client/cache/listers.go b/pkg/client/cache/listers.go new file mode 100644 index 00000000000..feacc11e7f8 --- /dev/null +++ b/pkg/client/cache/listers.go @@ -0,0 +1,78 @@ +/* +Copyright 2014 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cache + +import ( + "fmt" + + "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" +) + +// TODO: generate these classes and methods for all resources of interest using +// a script. Can use "go generate" once 1.4 is supported by all users. + +// StoreToPodLister makes a Store have the List method of the client.PodInterface +// The Store must contain (only) Pods. +// +// Example: +// s := cache.NewStore() +// XXX NewReflector(... s ...) +// l := StoreToPodLister{s} +// l.List() +type StoreToPodLister struct { + Store +} + +// TODO Get rid of the selector because that is confusing because the user might not realize that there has already been +// some selection at the caching stage. Also, consistency will facilitate code generation. +// TODO: Rename to List() instead of ListPods() for consistency with other resources and with pkg/client.. +func (s *StoreToPodLister) ListPods(selector labels.Selector) (pods []api.Pod, err error) { + for _, m := range s.List() { + pod := m.(*api.Pod) + if selector.Matches(labels.Set(pod.Labels)) { + pods = append(pods, *pod) + } + } + return pods, nil +} + +// StoreToNodeLister makes a Store have the List method of the client.NodeInterface +// The Store must contain (only) Nodes. +type StoreToNodeLister struct { + Store +} + +func (s *StoreToNodeLister) List() (machines api.NodeList, err error) { + for _, m := range s.Store.List() { + machines.Items = append(machines.Items, *(m.(*api.Node))) + } + return machines, nil +} + +// TODO Move this back to scheduler as a helper function that takes a Store, +// rather than a method of StoreToNodeLister. +// GetNodeInfo returns cached data for the minion 'id'. +func (s *StoreToNodeLister) GetNodeInfo(id string) (*api.Node, error) { + if minion, ok := s.Get(id); ok { + return minion.(*api.Node), nil + } + return nil, fmt.Errorf("minion '%v' is not in cache", id) +} + +// TODO: add StoreToServiceLister for use in kube-proxy and kubelet. +// TODO: add StoreToServiceLister for use in kube-proxy. diff --git a/pkg/client/cache/listers_test.go b/pkg/client/cache/listers_test.go new file mode 100644 index 00000000000..408fa66b9a9 --- /dev/null +++ b/pkg/client/cache/listers_test.go @@ -0,0 +1,76 @@ +/* +Copyright 2015 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cache + +import ( + "testing" + + "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" + "github.com/GoogleCloudPlatform/kubernetes/pkg/util" +) + +func TestStoreToMinionLister(t *testing.T) { + store := NewStore() + ids := util.NewStringSet("foo", "bar", "baz") + for id := range ids { + store.Add(id, &api.Node{ObjectMeta: api.ObjectMeta{Name: id}}) + } + sml := StoreToNodeLister{store} + + gotNodes, err := sml.List() + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + got := make([]string, len(gotNodes.Items)) + for ix := range gotNodes.Items { + got[ix] = gotNodes.Items[ix].Name + } + if !ids.HasAll(got...) || len(got) != len(ids) { + t.Errorf("Expected %v, got %v", ids, got) + } +} + +func TestStoreToPodLister(t *testing.T) { + store := NewStore() + ids := []string{"foo", "bar", "baz"} + for _, id := range ids { + store.Add(id, &api.Pod{ + ObjectMeta: api.ObjectMeta{ + Name: id, + Labels: map[string]string{"name": id}, + }, + }) + } + spl := StoreToPodLister{store} + + for _, id := range ids { + got, err := spl.ListPods(labels.Set{"name": id}.AsSelector()) + if err != nil { + t.Errorf("Unexpected error: %v", err) + continue + } + if e, a := 1, len(got); e != a { + t.Errorf("Expected %v, got %v", e, a) + continue + } + if e, a := id, got[0].Name; e != a { + t.Errorf("Expected %v, got %v", e, a) + continue + } + } +} diff --git a/plugin/pkg/scheduler/factory/factory.go b/plugin/pkg/scheduler/factory/factory.go index a7c18c9b01e..a469242c8c9 100644 --- a/plugin/pkg/scheduler/factory/factory.go +++ b/plugin/pkg/scheduler/factory/factory.go @@ -19,7 +19,6 @@ limitations under the License. package factory import ( - "fmt" "math/rand" "sync" "time" @@ -38,8 +37,8 @@ import ( ) var ( - PodLister = &storeToPodLister{cache.NewStore()} - MinionLister = &storeToNodeLister{cache.NewStore()} + PodLister = &cache.StoreToPodLister{cache.NewStore()} + MinionLister = &cache.StoreToNodeLister{cache.NewStore()} ) // ConfigFactory knows how to fill out a scheduler config with its support functions. @@ -48,9 +47,9 @@ type ConfigFactory struct { // queue for pods that need scheduling PodQueue *cache.FIFO // a means to list all scheduled pods - PodLister *storeToPodLister + PodLister *cache.StoreToPodLister // a means to list all minions - MinionLister *storeToNodeLister + MinionLister *cache.StoreToNodeLister } // NewConfigFactory initializes the factory. @@ -227,41 +226,6 @@ func (factory *ConfigFactory) makeDefaultErrorFunc(backoff *podBackoff, podQueue } } -// storeToNodeLister turns a store into a minion lister. The store must contain (only) minions. -type storeToNodeLister struct { - cache.Store -} - -func (s *storeToNodeLister) List() (machines api.NodeList, err error) { - for _, m := range s.Store.List() { - machines.Items = append(machines.Items, *(m.(*api.Node))) - } - return machines, nil -} - -// GetNodeInfo returns cached data for the minion 'id'. -func (s *storeToNodeLister) GetNodeInfo(id string) (*api.Node, error) { - if minion, ok := s.Get(id); ok { - return minion.(*api.Node), nil - } - return nil, fmt.Errorf("minion '%v' is not in cache", id) -} - -// storeToPodLister turns a store into a pod lister. The store must contain (only) pods. -type storeToPodLister struct { - cache.Store -} - -func (s *storeToPodLister) ListPods(selector labels.Selector) (pods []api.Pod, err error) { - for _, m := range s.List() { - pod := m.(*api.Pod) - if selector.Matches(labels.Set(pod.Labels)) { - pods = append(pods, *pod) - } - } - return pods, nil -} - // nodeEnumerator allows a cache.Poller to enumerate items in an api.NodeList type nodeEnumerator struct { *api.NodeList diff --git a/plugin/pkg/scheduler/factory/factory_test.go b/plugin/pkg/scheduler/factory/factory_test.go index 6fe76fa8601..1222b04ad5b 100644 --- a/plugin/pkg/scheduler/factory/factory_test.go +++ b/plugin/pkg/scheduler/factory/factory_test.go @@ -29,7 +29,6 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/api/testapi" "github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/client/cache" - "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" ) @@ -239,57 +238,6 @@ func TestDefaultErrorFunc(t *testing.T) { } } -func TestStoreToMinionLister(t *testing.T) { - store := cache.NewStore() - ids := util.NewStringSet("foo", "bar", "baz") - for id := range ids { - store.Add(id, &api.Node{ObjectMeta: api.ObjectMeta{Name: id}}) - } - sml := storeToNodeLister{store} - - gotNodes, err := sml.List() - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } - got := make([]string, len(gotNodes.Items)) - for ix := range gotNodes.Items { - got[ix] = gotNodes.Items[ix].Name - } - if !ids.HasAll(got...) || len(got) != len(ids) { - t.Errorf("Expected %v, got %v", ids, got) - } -} - -func TestStoreToPodLister(t *testing.T) { - store := cache.NewStore() - ids := []string{"foo", "bar", "baz"} - for _, id := range ids { - store.Add(id, &api.Pod{ - ObjectMeta: api.ObjectMeta{ - Name: id, - Labels: map[string]string{"name": id}, - }, - }) - } - spl := storeToPodLister{store} - - for _, id := range ids { - got, err := spl.ListPods(labels.Set{"name": id}.AsSelector()) - if err != nil { - t.Errorf("Unexpected error: %v", err) - continue - } - if e, a := 1, len(got); e != a { - t.Errorf("Expected %v, got %v", e, a) - continue - } - if e, a := id, got[0].Name; e != a { - t.Errorf("Expected %v, got %v", e, a) - continue - } - } -} - func TestMinionEnumerator(t *testing.T) { testList := &api.NodeList{ Items: []api.Node{