kubelet/dockershim/network: pass ipRange dynamically to the CNI plugin

CNI now supports passing ipRanges dynamically. Pass podCIDR so that
plugins no longer have to look it up.
This commit is contained in:
Casey Callendrello 2018-05-28 17:56:31 +02:00 committed by Casey Callendrello
parent c5d15cb0b8
commit 5d9ec20d7e
2 changed files with 72 additions and 3 deletions

View File

@ -50,6 +50,7 @@ type cniNetworkPlugin struct {
nsenterPath string
confDir string
binDirs []string
podCidr string
}
type cniNetwork struct {
@ -83,6 +84,11 @@ type cniBandwidthEntry struct {
EgressBurst int `json:"egressBurst,omitempty"`
}
// cniIpRange maps to the standard CNI ip range Capability
type cniIpRange struct {
Subnet string `json:"subnet"`
}
func SplitDirs(dirs string) []string {
// Use comma rather than colon to work better with Windows too
return strings.Split(dirs, ",")
@ -152,6 +158,8 @@ func getDefaultCNINetwork(confDir string, binDirs []string) (*cniNetwork, error)
continue
}
glog.V(4).Infof("Using CNI configuration file %s", confFile)
network := &cniNetwork{
name: confList.Name,
NetworkConfig: confList,
@ -199,9 +207,43 @@ func (plugin *cniNetworkPlugin) checkInitialized() error {
if plugin.getDefaultNetwork() == nil {
return errors.New("cni config uninitialized")
}
// If the CNI configuration has the ipRanges capability, we need a PodCIDR assigned
for _, p := range plugin.getDefaultNetwork().NetworkConfig.Plugins {
if p.Network.Capabilities["ipRanges"] {
if plugin.podCidr == "" {
return errors.New("no PodCIDR set")
}
break
}
}
return nil
}
// Event handles any change events. The only event ever sent is the PodCIDR change.
// No network plugins support changing an already-set PodCIDR
func (plugin *cniNetworkPlugin) Event(name string, details map[string]interface{}) {
if name != network.NET_PLUGIN_EVENT_POD_CIDR_CHANGE {
return
}
plugin.Lock()
defer plugin.Unlock()
podCIDR, ok := details[network.NET_PLUGIN_EVENT_POD_CIDR_CHANGE_DETAIL_CIDR].(string)
if !ok {
glog.Warningf("%s event didn't contain pod CIDR", network.NET_PLUGIN_EVENT_POD_CIDR_CHANGE)
return
}
if plugin.podCidr != "" {
glog.Warningf("Ignoring subsequent pod CIDR update to %s", podCIDR)
return
}
plugin.podCidr = podCIDR
}
func (plugin *cniNetworkPlugin) Name() string {
return CNIPluginName
}
@ -346,5 +388,8 @@ func (plugin *cniNetworkPlugin) buildCNIRuntimeConf(podName string, podNs string
rt.CapabilityArgs["bandwidth"] = bandwidthParam
}
// Set the PodCIDR
rt.CapabilityArgs["ipRanges"] = [][]cniIpRange{{{Subnet: plugin.podCidr}}}
return rt, nil
}

View File

@ -61,7 +61,7 @@ func installPluginUnderTest(t *testing.T, testBinDir, testConfDir, testDataDir,
if err != nil {
t.Fatalf("Failed to install plugin %s: %v", confFile, err)
}
networkConfig := fmt.Sprintf(`{ "name": "%s", "type": "%s", "capabilities": {"portMappings": true, "bandwidth": true} }`, confName, binName)
networkConfig := fmt.Sprintf(`{ "name": "%s", "type": "%s", "capabilities": {"portMappings": true, "bandwidth": true, "ipRanges": true} }`, confName, binName)
_, err = f.WriteString(networkConfig)
if err != nil {
t.Fatalf("Failed to write network config file (%v)", err)
@ -218,6 +218,19 @@ func TestCNIPlugin(t *testing.T) {
mockLoCNI.On("AddNetworkList", cniPlugin.loNetwork.NetworkConfig, mock.AnythingOfType("*libcni.RuntimeConf")).Return(&types020.Result{IP4: &types020.IPConfig{IP: net.IPNet{IP: []byte{127, 0, 0, 1}}}}, nil)
// Check that status returns an error
if err := cniPlugin.Status(); err == nil {
t.Fatalf("cniPlugin returned non-err with no podCidr")
}
cniPlugin.Event(network.NET_PLUGIN_EVENT_POD_CIDR_CHANGE, map[string]interface{}{
network.NET_PLUGIN_EVENT_POD_CIDR_CHANGE_DETAIL_CIDR: "10.0.2.0/24",
})
if err := cniPlugin.Status(); err != nil {
t.Fatalf("unexpected status err: %v", err)
}
ports := map[string][]*hostport.PortMapping{
containerID.ID: {
{
@ -259,8 +272,9 @@ func TestCNIPlugin(t *testing.T) {
// Verify the correct network configuration was passed
inputConfig := struct {
RuntimeConfig struct {
Bandwidth map[string]interface{} `json:"bandwidth"`
PortMappings []map[string]interface{} `json:"portMappings"`
PortMappings []map[string]interface{} `json:"portMappings"`
Bandwidth map[string]interface{} `json:"bandwidth"`
IpRanges [][]map[string]interface{} `json:"ipRanges"`
} `json:"runtimeConfig"`
}{}
inputBytes, inerr := ioutil.ReadFile(inputFile)
@ -282,6 +296,16 @@ func TestCNIPlugin(t *testing.T) {
t.Errorf("mismatch in expected bandwidth. expected %v got %v", expectedBandwidth, inputConfig.RuntimeConfig.Bandwidth)
}
expectedIpRange := [][]map[string]interface{}{
{
{"subnet": "10.0.2.0/24"},
},
}
if !reflect.DeepEqual(inputConfig.RuntimeConfig.IpRanges, expectedIpRange) {
t.Errorf("mismatch in expected ipRange. expected %v got %v", expectedIpRange, inputConfig.RuntimeConfig.IpRanges)
}
// Get its IP address
status, err := plug.GetPodNetworkStatus("podNamespace", "podName", containerID)
if err != nil {