kubenet: Fix panic when teardown run before setup

Teardown can run before Setup when the kubelet is restarted... in that
case, the shaper was nil and thus calling the shaper resulted in a panic

This fixes that by ensuring the shaper is always set... +1 level of
indirection and all that.
This commit is contained in:
Euan Kemp 2016-05-26 19:07:20 -07:00
parent 2f5e738dc1
commit 7e0b9bfa66
2 changed files with 31 additions and 25 deletions

View File

@ -64,19 +64,19 @@ const (
type kubenetNetworkPlugin struct { type kubenetNetworkPlugin struct {
network.NoopNetworkPlugin network.NoopNetworkPlugin
host network.Host host network.Host
netConfig *libcni.NetworkConfig netConfig *libcni.NetworkConfig
loConfig *libcni.NetworkConfig loConfig *libcni.NetworkConfig
cniConfig libcni.CNI cniConfig libcni.CNI
shaper bandwidth.BandwidthShaper bandwidthShaper bandwidth.BandwidthShaper
mu sync.Mutex //Mutex for protecting podIPs map and netConfig mu sync.Mutex //Mutex for protecting podIPs map, netConfig, and shaper initialization
podIPs map[kubecontainer.ContainerID]string podIPs map[kubecontainer.ContainerID]string
MTU int MTU int
execer utilexec.Interface execer utilexec.Interface
nsenterPath string nsenterPath string
hairpinMode componentconfig.HairpinMode hairpinMode componentconfig.HairpinMode
hostPortMap map[hostport]closeable hostPortMap map[hostport]closeable
iptables utiliptables.Interface iptables utiliptables.Interface
} }
func NewPlugin() network.NetworkPlugin { func NewPlugin() network.NetworkPlugin {
@ -335,19 +335,13 @@ func (plugin *kubenetNetworkPlugin) SetUpPod(namespace string, name string, id k
} }
} }
// The first SetUpPod call creates the bridge; ensure shaping is enabled // The first SetUpPod call creates the bridge; get a shaper for the sake of
if plugin.shaper == nil { // initialization
plugin.shaper = bandwidth.NewTCShaper(BridgeName) shaper := plugin.shaper()
if plugin.shaper == nil {
return fmt.Errorf("Failed to create bandwidth shaper!")
}
plugin.ensureBridgeTxQueueLen()
plugin.shaper.ReconcileInterface()
}
if egress != nil || ingress != nil { if egress != nil || ingress != nil {
ipAddr := plugin.podIPs[id] ipAddr := plugin.podIPs[id]
if err := plugin.shaper.ReconcileCIDR(fmt.Sprintf("%s/32", ipAddr), egress, ingress); err != nil { if err := shaper.ReconcileCIDR(fmt.Sprintf("%s/32", ipAddr), egress, ingress); err != nil {
return fmt.Errorf("Failed to add pod to shaper: %v", err) return fmt.Errorf("Failed to add pod to shaper: %v", err)
} }
} }
@ -374,7 +368,7 @@ func (plugin *kubenetNetworkPlugin) TearDownPod(namespace string, name string, i
if hasIP { if hasIP {
glog.V(5).Infof("Removing pod IP %s from shaper", podIP) glog.V(5).Infof("Removing pod IP %s from shaper", podIP)
// shaper wants /32 // shaper wants /32
if err := plugin.shaper.Reset(fmt.Sprintf("%s/32", podIP)); err != nil { if err := plugin.shaper().Reset(fmt.Sprintf("%s/32", podIP)); err != nil {
glog.Warningf("Failed to remove pod IP %s from shaper: %v", podIP, err) glog.Warningf("Failed to remove pod IP %s from shaper: %v", podIP, err)
} }
} }
@ -811,3 +805,15 @@ func (plugin *kubenetNetworkPlugin) cleanupHostportMap(containerPortMap map[api.
} }
} }
} }
// shaper retrieves the bandwidth shaper and, if it hasn't been fetched before,
// initializes it and ensures the bridge is appropriately configured
// This function should only be called while holding the `plugin.mu` lock
func (plugin *kubenetNetworkPlugin) shaper() bandwidth.BandwidthShaper {
if plugin.bandwidthShaper == nil {
plugin.bandwidthShaper = bandwidth.NewTCShaper(BridgeName)
plugin.ensureBridgeTxQueueLen()
plugin.bandwidthShaper.ReconcileInterface()
}
return plugin.bandwidthShaper
}

View File

@ -135,8 +135,8 @@ func TestTeardownCallsShaper(t *testing.T) {
mockcni := &mock_cni.MockCNI{} mockcni := &mock_cni.MockCNI{}
kubenet := newFakeKubenetPlugin(map[kubecontainer.ContainerID]string{}, fexec, fhost) kubenet := newFakeKubenetPlugin(map[kubecontainer.ContainerID]string{}, fexec, fhost)
kubenet.cniConfig = mockcni kubenet.cniConfig = mockcni
kubenet.shaper = fshaper
kubenet.iptables = ipttest.NewFake() kubenet.iptables = ipttest.NewFake()
kubenet.bandwidthShaper = fshaper
mockcni.On("DelNetwork", mock.AnythingOfType("*libcni.NetworkConfig"), mock.AnythingOfType("*libcni.RuntimeConf")).Return(nil) mockcni.On("DelNetwork", mock.AnythingOfType("*libcni.NetworkConfig"), mock.AnythingOfType("*libcni.RuntimeConf")).Return(nil)