Close all kubelet->API connections on heartbeat failure

parent 44a14b2d
...@@ -537,7 +537,7 @@ func run(s *options.KubeletServer, kubeDeps *kubelet.Dependencies) (err error) { ...@@ -537,7 +537,7 @@ func run(s *options.KubeletServer, kubeDeps *kubelet.Dependencies) (err error) {
// we set exitAfter to five minutes because we use this client configuration to request new certs - if we are unable // we set exitAfter to five minutes because we use this client configuration to request new certs - if we are unable
// to request new certs, we will be unable to continue normal operation. Exiting the process allows a wrapper // to request new certs, we will be unable to continue normal operation. Exiting the process allows a wrapper
// or the bootstrapping credentials to potentially lay down new initial config. // or the bootstrapping credentials to potentially lay down new initial config.
_, err := kubeletcertificate.UpdateTransport(wait.NeverStop, clientConfig, clientCertificateManager, 5*time.Minute) closeAllConns, err := kubeletcertificate.UpdateTransport(wait.NeverStop, clientConfig, clientCertificateManager, 5*time.Minute)
if err != nil { if err != nil {
return err return err
} }
...@@ -577,6 +577,7 @@ func run(s *options.KubeletServer, kubeDeps *kubelet.Dependencies) (err error) { ...@@ -577,6 +577,7 @@ func run(s *options.KubeletServer, kubeDeps *kubelet.Dependencies) (err error) {
kubeDeps.ExternalKubeClient = externalKubeClient kubeDeps.ExternalKubeClient = externalKubeClient
if heartbeatClient != nil { if heartbeatClient != nil {
kubeDeps.HeartbeatClient = heartbeatClient kubeDeps.HeartbeatClient = heartbeatClient
kubeDeps.OnHeartbeatFailure = closeAllConns
} }
if eventClient != nil { if eventClient != nil {
kubeDeps.EventClient = eventClient kubeDeps.EventClient = eventClient
......
...@@ -237,6 +237,7 @@ type Dependencies struct { ...@@ -237,6 +237,7 @@ type Dependencies struct {
DockerClientConfig *dockershim.ClientConfig DockerClientConfig *dockershim.ClientConfig
EventClient v1core.EventsGetter EventClient v1core.EventsGetter
HeartbeatClient v1core.CoreV1Interface HeartbeatClient v1core.CoreV1Interface
OnHeartbeatFailure func()
KubeClient clientset.Interface KubeClient clientset.Interface
ExternalKubeClient clientset.Interface ExternalKubeClient clientset.Interface
Mounter mount.Interface Mounter mount.Interface
...@@ -493,6 +494,7 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration, ...@@ -493,6 +494,7 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
nodeName: nodeName, nodeName: nodeName,
kubeClient: kubeDeps.KubeClient, kubeClient: kubeDeps.KubeClient,
heartbeatClient: kubeDeps.HeartbeatClient, heartbeatClient: kubeDeps.HeartbeatClient,
onRepeatedHeartbeatFailure: kubeDeps.OnHeartbeatFailure,
rootDirectory: rootDirectory, rootDirectory: rootDirectory,
resyncInterval: kubeCfg.SyncFrequency.Duration, resyncInterval: kubeCfg.SyncFrequency.Duration,
sourcesReady: config.NewSourcesReady(kubeDeps.PodConfig.SeenAllSources), sourcesReady: config.NewSourcesReady(kubeDeps.PodConfig.SeenAllSources),
...@@ -935,6 +937,9 @@ type Kubelet struct { ...@@ -935,6 +937,9 @@ type Kubelet struct {
iptClient utilipt.Interface iptClient utilipt.Interface
rootDirectory string rootDirectory string
// onRepeatedHeartbeatFailure is called when a heartbeat operation fails more than once. optional.
onRepeatedHeartbeatFailure func()
// podWorkers handle syncing Pods in response to events. // podWorkers handle syncing Pods in response to events.
podWorkers PodWorkers podWorkers PodWorkers
......
...@@ -371,6 +371,9 @@ func (kl *Kubelet) syncNodeStatus() { ...@@ -371,6 +371,9 @@ func (kl *Kubelet) syncNodeStatus() {
func (kl *Kubelet) updateNodeStatus() error { func (kl *Kubelet) updateNodeStatus() error {
for i := 0; i < nodeStatusUpdateRetry; i++ { for i := 0; i < nodeStatusUpdateRetry; i++ {
if err := kl.tryUpdateNodeStatus(i); err != nil { if err := kl.tryUpdateNodeStatus(i); err != nil {
if i > 0 && kl.onRepeatedHeartbeatFailure != nil {
kl.onRepeatedHeartbeatFailure()
}
glog.Errorf("Error updating node status, will retry: %v", err) glog.Errorf("Error updating node status, will retry: %v", err)
} else { } else {
return nil return nil
......
...@@ -593,6 +593,7 @@ func TestUpdateExistingNodeStatus(t *testing.T) { ...@@ -593,6 +593,7 @@ func TestUpdateExistingNodeStatus(t *testing.T) {
func TestUpdateExistingNodeStatusTimeout(t *testing.T) { func TestUpdateExistingNodeStatusTimeout(t *testing.T) {
attempts := int64(0) attempts := int64(0)
failureCallbacks := int64(0)
// set up a listener that hangs connections // set up a listener that hangs connections
ln, err := net.Listen("tcp", "127.0.0.1:0") ln, err := net.Listen("tcp", "127.0.0.1:0")
...@@ -623,6 +624,9 @@ func TestUpdateExistingNodeStatusTimeout(t *testing.T) { ...@@ -623,6 +624,9 @@ func TestUpdateExistingNodeStatusTimeout(t *testing.T) {
kubelet := testKubelet.kubelet kubelet := testKubelet.kubelet
kubelet.kubeClient = nil // ensure only the heartbeat client is used kubelet.kubeClient = nil // ensure only the heartbeat client is used
kubelet.heartbeatClient, err = v1core.NewForConfig(config) kubelet.heartbeatClient, err = v1core.NewForConfig(config)
kubelet.onRepeatedHeartbeatFailure = func() {
atomic.AddInt64(&failureCallbacks, 1)
}
kubelet.containerManager = &localCM{ kubelet.containerManager = &localCM{
ContainerManager: cm.NewStubContainerManager(), ContainerManager: cm.NewStubContainerManager(),
allocatableReservation: v1.ResourceList{ allocatableReservation: v1.ResourceList{
...@@ -642,6 +646,10 @@ func TestUpdateExistingNodeStatusTimeout(t *testing.T) { ...@@ -642,6 +646,10 @@ func TestUpdateExistingNodeStatusTimeout(t *testing.T) {
if actualAttempts := atomic.LoadInt64(&attempts); actualAttempts != nodeStatusUpdateRetry { if actualAttempts := atomic.LoadInt64(&attempts); actualAttempts != nodeStatusUpdateRetry {
t.Errorf("Expected %d attempts, got %d", nodeStatusUpdateRetry, actualAttempts) t.Errorf("Expected %d attempts, got %d", nodeStatusUpdateRetry, actualAttempts)
} }
// should have gotten multiple failure callbacks
if actualFailureCallbacks := atomic.LoadInt64(&failureCallbacks); actualFailureCallbacks < (nodeStatusUpdateRetry - 1) {
t.Errorf("Expected %d failure callbacks, got %d", (nodeStatusUpdateRetry - 1), actualFailureCallbacks)
}
} }
func TestUpdateNodeStatusWithRuntimeStateError(t *testing.T) { func TestUpdateNodeStatusWithRuntimeStateError(t *testing.T) {
......
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