mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-01 07:47:56 +00:00
Add a caching layer, so we don't pound cloud providers for ip addresses.
This commit is contained in:
parent
d131ad640a
commit
a115840e4f
@ -36,6 +36,23 @@ import (
|
|||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ipCacheEntry struct {
|
||||||
|
ip string
|
||||||
|
lastUpdate time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
type ipCache map[string]ipCacheEntry
|
||||||
|
|
||||||
|
type clock interface {
|
||||||
|
Now() time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
type realClock struct{}
|
||||||
|
|
||||||
|
func (r realClock) Now() time.Time {
|
||||||
|
return time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
// REST implements the RESTStorage interface in terms of a PodRegistry.
|
// REST implements the RESTStorage interface in terms of a PodRegistry.
|
||||||
type REST struct {
|
type REST struct {
|
||||||
cloudProvider cloudprovider.Interface
|
cloudProvider cloudprovider.Interface
|
||||||
@ -45,6 +62,8 @@ type REST struct {
|
|||||||
podPollPeriod time.Duration
|
podPollPeriod time.Duration
|
||||||
registry Registry
|
registry Registry
|
||||||
minions client.MinionInterface
|
minions client.MinionInterface
|
||||||
|
ipCache ipCache
|
||||||
|
clock clock
|
||||||
}
|
}
|
||||||
|
|
||||||
type RESTConfig struct {
|
type RESTConfig struct {
|
||||||
@ -64,6 +83,8 @@ func NewREST(config *RESTConfig) *REST {
|
|||||||
podPollPeriod: time.Second * 10,
|
podPollPeriod: time.Second * 10,
|
||||||
registry: config.Registry,
|
registry: config.Registry,
|
||||||
minions: config.Minions,
|
minions: config.Minions,
|
||||||
|
ipCache: ipCache{},
|
||||||
|
clock: realClock{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +133,7 @@ func (rs *REST) Get(ctx api.Context, id string) (runtime.Object, error) {
|
|||||||
}
|
}
|
||||||
pod.CurrentState.Status = status
|
pod.CurrentState.Status = status
|
||||||
}
|
}
|
||||||
pod.CurrentState.HostIP = getInstanceIP(rs.cloudProvider, pod.CurrentState.Host)
|
pod.CurrentState.HostIP = rs.getInstanceIP(pod.CurrentState.Host)
|
||||||
return pod, err
|
return pod, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,7 +165,7 @@ func (rs *REST) List(ctx api.Context, label, field labels.Selector) (runtime.Obj
|
|||||||
return pod, err
|
return pod, err
|
||||||
}
|
}
|
||||||
pod.CurrentState.Status = status
|
pod.CurrentState.Status = status
|
||||||
pod.CurrentState.HostIP = getInstanceIP(rs.cloudProvider, pod.CurrentState.Host)
|
pod.CurrentState.HostIP = rs.getInstanceIP(pod.CurrentState.Host)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pods, err
|
return pods, err
|
||||||
@ -212,7 +233,22 @@ func (rs *REST) fillPodInfo(pod *api.Pod) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getInstanceIP(cloud cloudprovider.Interface, host string) string {
|
func (rs *REST) getInstanceIP(host string) string {
|
||||||
|
data, ok := rs.ipCache[host]
|
||||||
|
now := rs.clock.Now()
|
||||||
|
|
||||||
|
if !ok || now.Sub(data.lastUpdate) > (30*time.Second) {
|
||||||
|
ip := getInstanceIPFromCloud(rs.cloudProvider, host)
|
||||||
|
data = ipCacheEntry{
|
||||||
|
ip: ip,
|
||||||
|
lastUpdate: now,
|
||||||
|
}
|
||||||
|
rs.ipCache[host] = data
|
||||||
|
}
|
||||||
|
return data.ip
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInstanceIPFromCloud(cloud cloudprovider.Interface, host string) string {
|
||||||
if cloud == nil {
|
if cloud == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -163,6 +163,14 @@ func TestListEmptyPodList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type fakeClock struct {
|
||||||
|
t time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fakeClock) Now() time.Time {
|
||||||
|
return f.t
|
||||||
|
}
|
||||||
|
|
||||||
func TestListPodList(t *testing.T) {
|
func TestListPodList(t *testing.T) {
|
||||||
podRegistry := registrytest.NewPodRegistry(nil)
|
podRegistry := registrytest.NewPodRegistry(nil)
|
||||||
podRegistry.Pods = &api.PodList{
|
podRegistry.Pods = &api.PodList{
|
||||||
@ -181,6 +189,8 @@ func TestListPodList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
storage := REST{
|
storage := REST{
|
||||||
registry: podRegistry,
|
registry: podRegistry,
|
||||||
|
ipCache: ipCache{},
|
||||||
|
clock: &fakeClock{},
|
||||||
}
|
}
|
||||||
ctx := api.NewContext()
|
ctx := api.NewContext()
|
||||||
podsObj, err := storage.List(ctx, labels.Everything(), labels.Everything())
|
podsObj, err := storage.List(ctx, labels.Everything(), labels.Everything())
|
||||||
@ -222,6 +232,8 @@ func TestListPodListSelection(t *testing.T) {
|
|||||||
}
|
}
|
||||||
storage := REST{
|
storage := REST{
|
||||||
registry: podRegistry,
|
registry: podRegistry,
|
||||||
|
ipCache: ipCache{},
|
||||||
|
clock: &fakeClock{},
|
||||||
}
|
}
|
||||||
ctx := api.NewContext()
|
ctx := api.NewContext()
|
||||||
|
|
||||||
@ -311,6 +323,8 @@ func TestGetPod(t *testing.T) {
|
|||||||
podRegistry.Pod = &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
|
podRegistry.Pod = &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
|
||||||
storage := REST{
|
storage := REST{
|
||||||
registry: podRegistry,
|
registry: podRegistry,
|
||||||
|
ipCache: ipCache{},
|
||||||
|
clock: &fakeClock{},
|
||||||
}
|
}
|
||||||
ctx := api.NewContext()
|
ctx := api.NewContext()
|
||||||
obj, err := storage.Get(ctx, "foo")
|
obj, err := storage.Get(ctx, "foo")
|
||||||
@ -328,9 +342,14 @@ func TestGetPodCloud(t *testing.T) {
|
|||||||
fakeCloud := &fake_cloud.FakeCloud{}
|
fakeCloud := &fake_cloud.FakeCloud{}
|
||||||
podRegistry := registrytest.NewPodRegistry(nil)
|
podRegistry := registrytest.NewPodRegistry(nil)
|
||||||
podRegistry.Pod = &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
|
podRegistry.Pod = &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
|
||||||
|
|
||||||
|
clock := &fakeClock{t: time.Now()}
|
||||||
|
|
||||||
storage := REST{
|
storage := REST{
|
||||||
registry: podRegistry,
|
registry: podRegistry,
|
||||||
cloudProvider: fakeCloud,
|
cloudProvider: fakeCloud,
|
||||||
|
ipCache: ipCache{},
|
||||||
|
clock: clock,
|
||||||
}
|
}
|
||||||
ctx := api.NewContext()
|
ctx := api.NewContext()
|
||||||
obj, err := storage.Get(ctx, "foo")
|
obj, err := storage.Get(ctx, "foo")
|
||||||
@ -342,9 +361,25 @@ func TestGetPodCloud(t *testing.T) {
|
|||||||
if e, a := podRegistry.Pod, pod; !reflect.DeepEqual(e, a) {
|
if e, a := podRegistry.Pod, pod; !reflect.DeepEqual(e, a) {
|
||||||
t.Errorf("Unexpected pod. Expected %#v, Got %#v", e, a)
|
t.Errorf("Unexpected pod. Expected %#v, Got %#v", e, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This call should hit the cache, so we expect no additional calls to the cloud
|
||||||
|
obj, err = storage.Get(ctx, "foo")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
if len(fakeCloud.Calls) != 1 || fakeCloud.Calls[0] != "ip-address" {
|
if len(fakeCloud.Calls) != 1 || fakeCloud.Calls[0] != "ip-address" {
|
||||||
t.Errorf("Unexpected calls: %#v", fakeCloud.Calls)
|
t.Errorf("Unexpected calls: %#v", fakeCloud.Calls)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Advance the clock, this call should miss the cache, so expect one more call.
|
||||||
|
clock.t = clock.t.Add(60 * time.Second)
|
||||||
|
obj, err = storage.Get(ctx, "foo")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if len(fakeCloud.Calls) != 2 || fakeCloud.Calls[1] != "ip-address" {
|
||||||
|
t.Errorf("Unexpected calls: %#v", fakeCloud.Calls)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMakePodStatus(t *testing.T) {
|
func TestMakePodStatus(t *testing.T) {
|
||||||
|
Loading…
Reference in New Issue
Block a user