Commit 7da0378f authored by Brendan Burns's avatar Brendan Burns

Track the sources that the kubelet has seen, and only delete pods

when every source has been seen at least once.
parent bb289492
...@@ -53,6 +53,10 @@ type PodConfig struct { ...@@ -53,6 +53,10 @@ type PodConfig struct {
// the channel of denormalized changes passed to listeners // the channel of denormalized changes passed to listeners
updates chan kubelet.PodUpdate updates chan kubelet.PodUpdate
// contains the list of all configured sources
sourcesLock sync.Mutex
sources util.StringSet
} }
// NewPodConfig creates an object that can merge many configuration sources into a stream // NewPodConfig creates an object that can merge many configuration sources into a stream
...@@ -64,6 +68,7 @@ func NewPodConfig(mode PodConfigNotificationMode) *PodConfig { ...@@ -64,6 +68,7 @@ func NewPodConfig(mode PodConfigNotificationMode) *PodConfig {
pods: storage, pods: storage,
mux: config.NewMux(storage), mux: config.NewMux(storage),
updates: updates, updates: updates,
sources: util.StringSet{},
} }
return podConfig return podConfig
} }
...@@ -71,9 +76,22 @@ func NewPodConfig(mode PodConfigNotificationMode) *PodConfig { ...@@ -71,9 +76,22 @@ func NewPodConfig(mode PodConfigNotificationMode) *PodConfig {
// Channel creates or returns a config source channel. The channel // Channel creates or returns a config source channel. The channel
// only accepts PodUpdates // only accepts PodUpdates
func (c *PodConfig) Channel(source string) chan<- interface{} { func (c *PodConfig) Channel(source string) chan<- interface{} {
c.sourcesLock.Lock()
defer c.sourcesLock.Unlock()
c.sources.Insert(source)
return c.mux.Channel(source) return c.mux.Channel(source)
} }
// SeenAllSources returns true if this config has received a SET
// message from all configured sources, false otherwise.
func (c *PodConfig) SeenAllSources() bool {
if c.pods == nil {
return false
}
glog.V(6).Infof("Looking for %v, have seen %v", c.sources.List(), c.pods.sourcesSeen)
return c.pods.seenSources(c.sources.List()...)
}
// Updates returns a channel of updates to the configuration, properly denormalized. // Updates returns a channel of updates to the configuration, properly denormalized.
func (c *PodConfig) Updates() <-chan kubelet.PodUpdate { func (c *PodConfig) Updates() <-chan kubelet.PodUpdate {
return c.updates return c.updates
...@@ -98,6 +116,10 @@ type podStorage struct { ...@@ -98,6 +116,10 @@ type podStorage struct {
// on the updates channel // on the updates channel
updateLock sync.Mutex updateLock sync.Mutex
updates chan<- kubelet.PodUpdate updates chan<- kubelet.PodUpdate
// contains the set of all sources that have sent at least one SET
sourcesSeenLock sync.Mutex
sourcesSeen util.StringSet
} }
// TODO: PodConfigNotificationMode could be handled by a listener to the updates channel // TODO: PodConfigNotificationMode could be handled by a listener to the updates channel
...@@ -105,9 +127,10 @@ type podStorage struct { ...@@ -105,9 +127,10 @@ type podStorage struct {
// TODO: allow initialization of the current state of the store with snapshotted version. // TODO: allow initialization of the current state of the store with snapshotted version.
func newPodStorage(updates chan<- kubelet.PodUpdate, mode PodConfigNotificationMode) *podStorage { func newPodStorage(updates chan<- kubelet.PodUpdate, mode PodConfigNotificationMode) *podStorage {
return &podStorage{ return &podStorage{
pods: make(map[string]map[string]*api.BoundPod), pods: make(map[string]map[string]*api.BoundPod),
mode: mode, mode: mode,
updates: updates, updates: updates,
sourcesSeen: util.StringSet{},
} }
} }
...@@ -138,12 +161,12 @@ func (s *podStorage) Merge(source string, change interface{}) error { ...@@ -138,12 +161,12 @@ func (s *podStorage) Merge(source string, change interface{}) error {
s.updates <- *updates s.updates <- *updates
} }
if len(deletes.Pods) > 0 || len(adds.Pods) > 0 { if len(deletes.Pods) > 0 || len(adds.Pods) > 0 {
s.updates <- kubelet.PodUpdate{s.MergedState().([]api.BoundPod), kubelet.SET} s.updates <- kubelet.PodUpdate{s.MergedState().([]api.BoundPod), kubelet.SET, source}
} }
case PodConfigNotificationSnapshot: case PodConfigNotificationSnapshot:
if len(updates.Pods) > 0 || len(deletes.Pods) > 0 || len(adds.Pods) > 0 { if len(updates.Pods) > 0 || len(deletes.Pods) > 0 || len(adds.Pods) > 0 {
s.updates <- kubelet.PodUpdate{s.MergedState().([]api.BoundPod), kubelet.SET} s.updates <- kubelet.PodUpdate{s.MergedState().([]api.BoundPod), kubelet.SET, source}
} }
default: default:
...@@ -212,6 +235,7 @@ func (s *podStorage) merge(source string, change interface{}) (adds, updates, de ...@@ -212,6 +235,7 @@ func (s *podStorage) merge(source string, change interface{}) (adds, updates, de
case kubelet.SET: case kubelet.SET:
glog.V(4).Infof("Setting pods for source %s : %v", source, update) glog.V(4).Infof("Setting pods for source %s : %v", source, update)
s.markSourceSet(source)
// Clear the old map entries by just creating a new map // Clear the old map entries by just creating a new map
oldPods := pods oldPods := pods
pods = make(map[string]*api.BoundPod) pods = make(map[string]*api.BoundPod)
...@@ -254,6 +278,18 @@ func (s *podStorage) merge(source string, change interface{}) (adds, updates, de ...@@ -254,6 +278,18 @@ func (s *podStorage) merge(source string, change interface{}) (adds, updates, de
return adds, updates, deletes return adds, updates, deletes
} }
func (s *podStorage) markSourceSet(source string) {
s.sourcesSeenLock.Lock()
defer s.sourcesSeenLock.Unlock()
s.sourcesSeen.Insert(source)
}
func (s *podStorage) seenSources(sources ...string) bool {
s.sourcesSeenLock.Lock()
defer s.sourcesSeenLock.Unlock()
return s.sourcesSeen.HasAll(sources...)
}
func filterInvalidPods(pods []api.BoundPod, source string) (filtered []*api.BoundPod) { func filterInvalidPods(pods []api.BoundPod, source string) (filtered []*api.BoundPod) {
names := util.StringSet{} names := util.StringSet{}
for i := range pods { for i := range pods {
...@@ -280,7 +316,7 @@ func filterInvalidPods(pods []api.BoundPod, source string) (filtered []*api.Boun ...@@ -280,7 +316,7 @@ func filterInvalidPods(pods []api.BoundPod, source string) (filtered []*api.Boun
func (s *podStorage) Sync() { func (s *podStorage) Sync() {
s.updateLock.Lock() s.updateLock.Lock()
defer s.updateLock.Unlock() defer s.updateLock.Unlock()
s.updates <- kubelet.PodUpdate{s.MergedState().([]api.BoundPod), kubelet.SET} s.updates <- kubelet.PodUpdate{s.MergedState().([]api.BoundPod), kubelet.SET, kubelet.AllSource}
} }
// Object implements config.Accessor // Object implements config.Accessor
......
...@@ -79,7 +79,7 @@ func (s *sourceEtcd) run() { ...@@ -79,7 +79,7 @@ func (s *sourceEtcd) run() {
} }
glog.V(4).Infof("Received state from etcd watch: %+v", pods) glog.V(4).Infof("Received state from etcd watch: %+v", pods)
s.updates <- kubelet.PodUpdate{pods, kubelet.SET} s.updates <- kubelet.PodUpdate{pods, kubelet.SET, kubelet.EtcdSource}
} }
} }
} }
......
...@@ -73,14 +73,14 @@ func (s *sourceFile) extractFromPath() error { ...@@ -73,14 +73,14 @@ func (s *sourceFile) extractFromPath() error {
if err != nil { if err != nil {
return err return err
} }
s.updates <- kubelet.PodUpdate{pods, kubelet.SET} s.updates <- kubelet.PodUpdate{pods, kubelet.SET, kubelet.FileSource}
case statInfo.Mode().IsRegular(): case statInfo.Mode().IsRegular():
pod, err := extractFromFile(path) pod, err := extractFromFile(path)
if err != nil { if err != nil {
return err return err
} }
s.updates <- kubelet.PodUpdate{[]api.BoundPod{pod}, kubelet.SET} s.updates <- kubelet.PodUpdate{[]api.BoundPod{pod}, kubelet.SET, kubelet.FileSource}
default: default:
return fmt.Errorf("path is not a directory or file") return fmt.Errorf("path is not a directory or file")
......
...@@ -119,7 +119,7 @@ func TestReadFromFile(t *testing.T) { ...@@ -119,7 +119,7 @@ func TestReadFromFile(t *testing.T) {
select { select {
case got := <-ch: case got := <-ch:
update := got.(kubelet.PodUpdate) update := got.(kubelet.PodUpdate)
expected := CreatePodUpdate(kubelet.SET, api.BoundPod{ expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource, api.BoundPod{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: simpleSubdomainSafeHash(file.Name()), Name: simpleSubdomainSafeHash(file.Name()),
UID: simpleSubdomainSafeHash(file.Name()), UID: simpleSubdomainSafeHash(file.Name()),
...@@ -170,7 +170,7 @@ func TestExtractFromValidDataFile(t *testing.T) { ...@@ -170,7 +170,7 @@ func TestExtractFromValidDataFile(t *testing.T) {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
update := (<-ch).(kubelet.PodUpdate) update := (<-ch).(kubelet.PodUpdate)
expected := CreatePodUpdate(kubelet.SET, expectedPod) expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource, expectedPod)
if !reflect.DeepEqual(expected, update) { if !reflect.DeepEqual(expected, update) {
t.Errorf("Expected %#v, Got %#v", expected, update) t.Errorf("Expected %#v, Got %#v", expected, update)
} }
...@@ -191,7 +191,7 @@ func TestExtractFromEmptyDir(t *testing.T) { ...@@ -191,7 +191,7 @@ func TestExtractFromEmptyDir(t *testing.T) {
} }
update := (<-ch).(kubelet.PodUpdate) update := (<-ch).(kubelet.PodUpdate)
expected := CreatePodUpdate(kubelet.SET) expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource)
if !reflect.DeepEqual(expected, update) { if !reflect.DeepEqual(expected, update) {
t.Errorf("Expected %#v, Got %#v", expected, update) t.Errorf("Expected %#v, Got %#v", expected, update)
} }
...@@ -239,7 +239,7 @@ func TestExtractFromDir(t *testing.T) { ...@@ -239,7 +239,7 @@ func TestExtractFromDir(t *testing.T) {
} }
update := (<-ch).(kubelet.PodUpdate) update := (<-ch).(kubelet.PodUpdate)
expected := CreatePodUpdate(kubelet.SET, pods...) expected := CreatePodUpdate(kubelet.SET, kubelet.FileSource, pods...)
sort.Sort(sortedPods(update.Pods)) sort.Sort(sortedPods(update.Pods))
sort.Sort(sortedPods(expected.Pods)) sort.Sort(sortedPods(expected.Pods))
if !reflect.DeepEqual(expected, update) { if !reflect.DeepEqual(expected, update) {
......
...@@ -97,7 +97,7 @@ func (s *sourceURL) extractFromURL() error { ...@@ -97,7 +97,7 @@ func (s *sourceURL) extractFromURL() error {
if len(pod.Namespace) == 0 { if len(pod.Namespace) == 0 {
pod.Namespace = api.NamespaceDefault pod.Namespace = api.NamespaceDefault
} }
s.updates <- kubelet.PodUpdate{[]api.BoundPod{pod}, kubelet.SET} s.updates <- kubelet.PodUpdate{[]api.BoundPod{pod}, kubelet.SET, kubelet.HTTPSource}
return nil return nil
} }
...@@ -138,7 +138,7 @@ func (s *sourceURL) extractFromURL() error { ...@@ -138,7 +138,7 @@ func (s *sourceURL) extractFromURL() error {
pod.Namespace = api.NamespaceDefault pod.Namespace = api.NamespaceDefault
} }
} }
s.updates <- kubelet.PodUpdate{boundPods.Items, kubelet.SET} s.updates <- kubelet.PodUpdate{boundPods.Items, kubelet.SET, kubelet.HTTPSource}
return nil return nil
} }
......
...@@ -124,6 +124,7 @@ func TestExtractFromHTTP(t *testing.T) { ...@@ -124,6 +124,7 @@ func TestExtractFromHTTP(t *testing.T) {
desc: "Single manifest", desc: "Single manifest",
manifests: api.ContainerManifest{Version: "v1beta1", ID: "foo"}, manifests: api.ContainerManifest{Version: "v1beta1", ID: "foo"},
expected: CreatePodUpdate(kubelet.SET, expected: CreatePodUpdate(kubelet.SET,
kubelet.HTTPSource,
api.BoundPod{ api.BoundPod{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "foo", Name: "foo",
...@@ -141,6 +142,7 @@ func TestExtractFromHTTP(t *testing.T) { ...@@ -141,6 +142,7 @@ func TestExtractFromHTTP(t *testing.T) {
{Version: "v1beta1", ID: "bar", Containers: []api.Container{{Name: "1", Image: "foo"}}}, {Version: "v1beta1", ID: "bar", Containers: []api.Container{{Name: "1", Image: "foo"}}},
}, },
expected: CreatePodUpdate(kubelet.SET, expected: CreatePodUpdate(kubelet.SET,
kubelet.HTTPSource,
api.BoundPod{ api.BoundPod{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "1", Name: "1",
...@@ -169,7 +171,7 @@ func TestExtractFromHTTP(t *testing.T) { ...@@ -169,7 +171,7 @@ func TestExtractFromHTTP(t *testing.T) {
{ {
desc: "Empty Array", desc: "Empty Array",
manifests: []api.ContainerManifest{}, manifests: []api.ContainerManifest{},
expected: CreatePodUpdate(kubelet.SET), expected: CreatePodUpdate(kubelet.SET, kubelet.HTTPSource),
}, },
} }
for _, testCase := range testCases { for _, testCase := range testCases {
......
...@@ -76,7 +76,7 @@ func TestGetContainerID(t *testing.T) { ...@@ -76,7 +76,7 @@ func TestGetContainerID(t *testing.T) {
t.Errorf("Failed to find container %#v", dockerContainer) t.Errorf("Failed to find container %#v", dockerContainer)
} }
fakeDocker.clearCalls() fakeDocker.ClearCalls()
dockerContainer, found, _ = dockerContainers.FindPodContainer("foobar", "", "foo") dockerContainer, found, _ = dockerContainers.FindPodContainer("foobar", "", "foo")
verifyCalls(t, fakeDocker, []string{}) verifyCalls(t, fakeDocker, []string{})
if dockerContainer != nil || found { if dockerContainer != nil || found {
......
...@@ -40,10 +40,14 @@ type FakeDockerClient struct { ...@@ -40,10 +40,14 @@ type FakeDockerClient struct {
VersionInfo docker.Env VersionInfo docker.Env
} }
func (f *FakeDockerClient) clearCalls() { func (f *FakeDockerClient) ClearCalls() {
f.Lock() f.Lock()
defer f.Unlock() defer f.Unlock()
f.called = []string{} f.called = []string{}
f.Stopped = []string{}
f.pulled = []string{}
f.Created = []string{}
f.Removed = []string{}
} }
func (f *FakeDockerClient) AssertCalls(calls []string) (err error) { func (f *FakeDockerClient) AssertCalls(calls []string) (err error) {
......
...@@ -53,6 +53,8 @@ type SyncHandler interface { ...@@ -53,6 +53,8 @@ type SyncHandler interface {
SyncPods([]api.BoundPod) error SyncPods([]api.BoundPod) error
} }
type SourcesReadyFn func() bool
type volumeMap map[string]volume.Interface type volumeMap map[string]volume.Interface
// New creates a new Kubelet for use in main // New creates a new Kubelet for use in main
...@@ -66,7 +68,8 @@ func NewMainKubelet( ...@@ -66,7 +68,8 @@ func NewMainKubelet(
pullQPS float32, pullQPS float32,
pullBurst int, pullBurst int,
minimumGCAge time.Duration, minimumGCAge time.Duration,
maxContainerCount int) *Kubelet { maxContainerCount int,
sourcesReady SourcesReadyFn) *Kubelet {
return &Kubelet{ return &Kubelet{
hostname: hn, hostname: hn,
dockerClient: dc, dockerClient: dc,
...@@ -82,6 +85,7 @@ func NewMainKubelet( ...@@ -82,6 +85,7 @@ func NewMainKubelet(
pullBurst: pullBurst, pullBurst: pullBurst,
minimumGCAge: minimumGCAge, minimumGCAge: minimumGCAge,
maxContainerCount: maxContainerCount, maxContainerCount: maxContainerCount,
sourcesReady: sourcesReady,
} }
} }
...@@ -112,6 +116,7 @@ type Kubelet struct { ...@@ -112,6 +116,7 @@ type Kubelet struct {
podWorkers *podWorkers podWorkers *podWorkers
resyncInterval time.Duration resyncInterval time.Duration
pods []api.BoundPod pods []api.BoundPod
sourcesReady SourcesReadyFn
// Needed to report events for containers belonging to deleted/modified pods. // Needed to report events for containers belonging to deleted/modified pods.
// Tracks references for reporting events // Tracks references for reporting events
...@@ -907,7 +912,12 @@ func (kl *Kubelet) SyncPods(pods []api.BoundPod) error { ...@@ -907,7 +912,12 @@ func (kl *Kubelet) SyncPods(pods []api.BoundPod) error {
} }
}) })
} }
if !kl.sourcesReady() {
// If the sources aren't ready, skip deletion, as we may accidentally delete pods
// for sources that haven't reported yet.
glog.V(4).Infof("Skipping deletes, sources aren't ready yet.")
return nil
}
// Kill any containers we don't need. // Kill any containers we don't need.
for _, container := range dockerContainers { for _, container := range dockerContainers {
// Don't kill containers that are in the desired pods. // Don't kill containers that are in the desired pods.
......
...@@ -55,6 +55,7 @@ func newTestKubelet(t *testing.T) (*Kubelet, *tools.FakeEtcdClient, *dockertools ...@@ -55,6 +55,7 @@ func newTestKubelet(t *testing.T) (*Kubelet, *tools.FakeEtcdClient, *dockertools
kubelet.etcdClient = fakeEtcdClient kubelet.etcdClient = fakeEtcdClient
kubelet.rootDirectory = "/tmp/kubelet" kubelet.rootDirectory = "/tmp/kubelet"
kubelet.podWorkers = newPodWorkers() kubelet.podWorkers = newPodWorkers()
kubelet.sourcesReady = func() bool { return true }
return kubelet, fakeEtcdClient, fakeDocker return kubelet, fakeEtcdClient, fakeDocker
} }
...@@ -513,6 +514,49 @@ func TestSyncPodsDeletesWithNoNetContainer(t *testing.T) { ...@@ -513,6 +514,49 @@ func TestSyncPodsDeletesWithNoNetContainer(t *testing.T) {
fakeDocker.Unlock() fakeDocker.Unlock()
} }
func TestSyncPodsDeletesWhenSourcesAreReady(t *testing.T) {
ready := false
kubelet, _, fakeDocker := newTestKubelet(t)
kubelet.sourcesReady = func() bool { return ready }
fakeDocker.ContainerList = []docker.APIContainers{
{
// the k8s prefix is required for the kubelet to manage the container
Names: []string{"/k8s_foo_bar.new.test"},
ID: "1234",
},
{
// network container
Names: []string{"/k8s_net_foo.new.test_"},
ID: "9876",
},
}
if err := kubelet.SyncPods([]api.BoundPod{}); err != nil {
t.Errorf("unexpected error: %v", err)
}
// Validate nothing happened.
verifyCalls(t, fakeDocker, []string{"list"})
fakeDocker.ClearCalls()
ready = true
if err := kubelet.SyncPods([]api.BoundPod{}); err != nil {
t.Errorf("unexpected error: %v", err)
}
verifyCalls(t, fakeDocker, []string{"list", "stop", "stop"})
// A map iteration is used to delete containers, so must not depend on
// order here.
expectedToStop := map[string]bool{
"1234": true,
"9876": true,
}
if len(fakeDocker.Stopped) != 2 ||
!expectedToStop[fakeDocker.Stopped[0]] ||
!expectedToStop[fakeDocker.Stopped[1]] {
t.Errorf("Wrong containers were stopped: %v", fakeDocker.Stopped)
}
}
func TestSyncPodsDeletes(t *testing.T) { func TestSyncPodsDeletes(t *testing.T) {
kubelet, _, fakeDocker := newTestKubelet(t) kubelet, _, fakeDocker := newTestKubelet(t)
fakeDocker.ContainerList = []docker.APIContainers{ fakeDocker.ContainerList = []docker.APIContainers{
......
...@@ -59,6 +59,7 @@ func ListenAndServeKubeletServer(host HostInterface, updates chan<- interface{}, ...@@ -59,6 +59,7 @@ func ListenAndServeKubeletServer(host HostInterface, updates chan<- interface{},
WriteTimeout: 5 * time.Minute, WriteTimeout: 5 * time.Minute,
MaxHeaderBytes: 1 << 20, MaxHeaderBytes: 1 << 20,
} }
updates <- PodUpdate{[]api.BoundPod{}, SET, ServerSource}
glog.Fatal(s.ListenAndServe()) glog.Fatal(s.ListenAndServe())
} }
...@@ -143,7 +144,7 @@ func (s *Server) handleContainer(w http.ResponseWriter, req *http.Request) { ...@@ -143,7 +144,7 @@ func (s *Server) handleContainer(w http.ResponseWriter, req *http.Request) {
if pod.UID == "" { if pod.UID == "" {
pod.UID = "1" pod.UID = "1"
} }
s.updates <- PodUpdate{[]api.BoundPod{pod}, SET} s.updates <- PodUpdate{[]api.BoundPod{pod}, SET, ServerSource}
} }
...@@ -166,8 +167,7 @@ func (s *Server) handleContainers(w http.ResponseWriter, req *http.Request) { ...@@ -166,8 +167,7 @@ func (s *Server) handleContainers(w http.ResponseWriter, req *http.Request) {
pods[i].Name = fmt.Sprintf("%d", i+1) pods[i].Name = fmt.Sprintf("%d", i+1)
pods[i].Spec = specs[i] pods[i].Spec = specs[i]
} }
s.updates <- PodUpdate{pods, SET} s.updates <- PodUpdate{pods, SET, ServerSource}
} }
// handleContainerLogs handles containerLogs request against the Kubelet // handleContainerLogs handles containerLogs request against the Kubelet
......
...@@ -36,6 +36,18 @@ const ( ...@@ -36,6 +36,18 @@ const (
REMOVE REMOVE
// Pods with the given ids have been updated in this source // Pods with the given ids have been updated in this source
UPDATE UPDATE
// These constants identify the sources of pods
// Updates from a file
FileSource = "file"
// Updates from etcd
EtcdSource = "etcd"
// Updates from querying a web page
HTTPSource = "http"
// Updates received to the kubelet server
ServerSource = "server"
// Updates from all sources
AllSource = "*"
) )
// PodUpdate defines an operation sent on the channel. You can add or remove single services by // PodUpdate defines an operation sent on the channel. You can add or remove single services by
...@@ -48,8 +60,9 @@ const ( ...@@ -48,8 +60,9 @@ const (
// functionally similar, this helps our unit tests properly check that the correct PodUpdates // functionally similar, this helps our unit tests properly check that the correct PodUpdates
// are generated. // are generated.
type PodUpdate struct { type PodUpdate struct {
Pods []api.BoundPod Pods []api.BoundPod
Op PodOperation Op PodOperation
Source string
} }
// GetPodFullName returns a name that uniquely identifies a pod across all config sources. // GetPodFullName returns a name that uniquely identifies a pod across all config sources.
......
...@@ -176,7 +176,7 @@ func RunKubelet(kcfg *KubeletConfig) { ...@@ -176,7 +176,7 @@ func RunKubelet(kcfg *KubeletConfig) {
} }
cfg := makePodSourceConfig(kcfg) cfg := makePodSourceConfig(kcfg)
k := createAndInitKubelet(kcfg) k := createAndInitKubelet(kcfg, cfg)
// process pods and exit. // process pods and exit.
if kcfg.Runonce { if kcfg.Runonce {
if _, err := k.RunOnce(cfg.Updates()); err != nil { if _, err := k.RunOnce(cfg.Updates()); err != nil {
...@@ -194,7 +194,7 @@ func startKubelet(k *kubelet.Kubelet, cfg *config.PodConfig, kc *KubeletConfig) ...@@ -194,7 +194,7 @@ func startKubelet(k *kubelet.Kubelet, cfg *config.PodConfig, kc *KubeletConfig)
// start the kubelet server // start the kubelet server
if kc.EnableServer { if kc.EnableServer {
go util.Forever(func() { go util.Forever(func() {
kubelet.ListenAndServeKubeletServer(k, cfg.Channel("http"), net.IP(kc.Address), kc.Port, kc.EnableDebuggingHandlers) kubelet.ListenAndServeKubeletServer(k, cfg.Channel(kubelet.ServerSource), net.IP(kc.Address), kc.Port, kc.EnableDebuggingHandlers)
}, 0) }, 0)
} }
} }
...@@ -205,17 +205,19 @@ func makePodSourceConfig(kc *KubeletConfig) *config.PodConfig { ...@@ -205,17 +205,19 @@ func makePodSourceConfig(kc *KubeletConfig) *config.PodConfig {
// define file config source // define file config source
if kc.ConfigFile != "" { if kc.ConfigFile != "" {
config.NewSourceFile(kc.ConfigFile, kc.FileCheckFrequency, cfg.Channel("file")) glog.Infof("Adding manifest file: %v", kc.ConfigFile)
config.NewSourceFile(kc.ConfigFile, kc.FileCheckFrequency, cfg.Channel(kubelet.FileSource))
} }
// define url config source // define url config source
if kc.ManifestURL != "" { if kc.ManifestURL != "" {
config.NewSourceURL(kc.ManifestURL, kc.HttpCheckFrequency, cfg.Channel("http")) glog.Infof("Adding manifest url: %v", kc.ManifestURL)
config.NewSourceURL(kc.ManifestURL, kc.HttpCheckFrequency, cfg.Channel(kubelet.HTTPSource))
} }
if kc.EtcdClient != nil { if kc.EtcdClient != nil {
glog.Infof("Watching for etcd configs at %v", kc.EtcdClient.GetCluster()) glog.Infof("Watching for etcd configs at %v", kc.EtcdClient.GetCluster())
config.NewSourceEtcd(config.EtcdKeyForHost(kc.Hostname), kc.EtcdClient, cfg.Channel("etcd")) config.NewSourceEtcd(config.EtcdKeyForHost(kc.Hostname), kc.EtcdClient, cfg.Channel(kubelet.EtcdSource))
} }
return cfg return cfg
} }
...@@ -247,7 +249,7 @@ type KubeletConfig struct { ...@@ -247,7 +249,7 @@ type KubeletConfig struct {
Runonce bool Runonce bool
} }
func createAndInitKubelet(kc *KubeletConfig) *kubelet.Kubelet { func createAndInitKubelet(kc *KubeletConfig, pc *config.PodConfig) *kubelet.Kubelet {
// TODO: block until all sources have delivered at least one update to the channel, or break the sync loop // TODO: block until all sources have delivered at least one update to the channel, or break the sync loop
// up into "per source" synchronizations // up into "per source" synchronizations
...@@ -261,7 +263,8 @@ func createAndInitKubelet(kc *KubeletConfig) *kubelet.Kubelet { ...@@ -261,7 +263,8 @@ func createAndInitKubelet(kc *KubeletConfig) *kubelet.Kubelet {
float32(kc.RegistryPullQPS), float32(kc.RegistryPullQPS),
kc.RegistryBurst, kc.RegistryBurst,
kc.MinimumGCAge, kc.MinimumGCAge,
kc.MaxContainerCount) kc.MaxContainerCount,
pc.SeenAllSources)
k.BirthCry() k.BirthCry()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment