forked from barak/tarpoon
Add glide.yaml and vendor deps
This commit is contained in:
parent
db918f12ad
commit
5b3d5e81bd
18880 changed files with 5166045 additions and 1 deletions
44
vendor/k8s.io/kubernetes/pkg/kubelet/network/BUILD
generated
vendored
Normal file
44
vendor/k8s.io/kubernetes/pkg/kubelet/network/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"network.go",
|
||||
"plugins.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/componentconfig:go_default_library",
|
||||
"//pkg/apis/meta/v1:go_default_library",
|
||||
"//pkg/client/clientset_generated/release_1_5:go_default_library",
|
||||
"//pkg/kubelet/container:go_default_library",
|
||||
"//pkg/util/errors:go_default_library",
|
||||
"//pkg/util/exec:go_default_library",
|
||||
"//pkg/util/sets:go_default_library",
|
||||
"//pkg/util/sysctl:go_default_library",
|
||||
"//pkg/util/validation:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["plugins_test.go"],
|
||||
library = "go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/apis/componentconfig:go_default_library",
|
||||
"//pkg/kubelet/network/testing:go_default_library",
|
||||
],
|
||||
)
|
||||
47
vendor/k8s.io/kubernetes/pkg/kubelet/network/cni/BUILD
generated
vendored
Normal file
47
vendor/k8s.io/kubernetes/pkg/kubelet/network/cni/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["cni.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/apis/componentconfig:go_default_library",
|
||||
"//pkg/kubelet/container:go_default_library",
|
||||
"//pkg/kubelet/network:go_default_library",
|
||||
"//pkg/util/exec:go_default_library",
|
||||
"//pkg/util/wait:go_default_library",
|
||||
"//vendor:github.com/containernetworking/cni/libcni",
|
||||
"//vendor:github.com/containernetworking/cni/pkg/types",
|
||||
"//vendor:github.com/golang/glog",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["cni_test.go"],
|
||||
library = "go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/componentconfig:go_default_library",
|
||||
"//pkg/client/clientset_generated/release_1_5:go_default_library",
|
||||
"//pkg/kubelet/container:go_default_library",
|
||||
"//pkg/kubelet/container/testing:go_default_library",
|
||||
"//pkg/kubelet/network:go_default_library",
|
||||
"//pkg/kubelet/network/cni/testing:go_default_library",
|
||||
"//pkg/util/exec:go_default_library",
|
||||
"//pkg/util/testing:go_default_library",
|
||||
"//vendor:github.com/containernetworking/cni/pkg/types",
|
||||
"//vendor:github.com/stretchr/testify/mock",
|
||||
],
|
||||
)
|
||||
296
vendor/k8s.io/kubernetes/pkg/kubelet/network/cni/cni.go
generated
vendored
Normal file
296
vendor/k8s.io/kubernetes/pkg/kubelet/network/cni/cni.go
generated
vendored
Normal file
|
|
@ -0,0 +1,296 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cni
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/containernetworking/cni/libcni"
|
||||
cnitypes "github.com/containernetworking/cni/pkg/types"
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kubernetes/pkg/apis/componentconfig"
|
||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
"k8s.io/kubernetes/pkg/kubelet/network"
|
||||
utilexec "k8s.io/kubernetes/pkg/util/exec"
|
||||
"k8s.io/kubernetes/pkg/util/wait"
|
||||
)
|
||||
|
||||
const (
|
||||
CNIPluginName = "cni"
|
||||
DefaultNetDir = "/etc/cni/net.d"
|
||||
DefaultCNIDir = "/opt/cni/bin"
|
||||
VendorCNIDirTemplate = "%s/opt/%s/bin"
|
||||
)
|
||||
|
||||
type cniNetworkPlugin struct {
|
||||
network.NoopNetworkPlugin
|
||||
|
||||
loNetwork *cniNetwork
|
||||
|
||||
sync.RWMutex
|
||||
defaultNetwork *cniNetwork
|
||||
|
||||
host network.Host
|
||||
execer utilexec.Interface
|
||||
nsenterPath string
|
||||
pluginDir string
|
||||
binDir string
|
||||
vendorCNIDirPrefix string
|
||||
}
|
||||
|
||||
type cniNetwork struct {
|
||||
name string
|
||||
NetworkConfig *libcni.NetworkConfig
|
||||
CNIConfig libcni.CNI
|
||||
}
|
||||
|
||||
func probeNetworkPluginsWithVendorCNIDirPrefix(pluginDir, binDir, vendorCNIDirPrefix string) []network.NetworkPlugin {
|
||||
if binDir == "" {
|
||||
binDir = DefaultCNIDir
|
||||
}
|
||||
plugin := &cniNetworkPlugin{
|
||||
defaultNetwork: nil,
|
||||
loNetwork: getLoNetwork(binDir, vendorCNIDirPrefix),
|
||||
execer: utilexec.New(),
|
||||
pluginDir: pluginDir,
|
||||
binDir: binDir,
|
||||
vendorCNIDirPrefix: vendorCNIDirPrefix,
|
||||
}
|
||||
|
||||
// sync NetworkConfig in best effort during probing.
|
||||
plugin.syncNetworkConfig()
|
||||
return []network.NetworkPlugin{plugin}
|
||||
}
|
||||
|
||||
func ProbeNetworkPlugins(pluginDir, binDir string) []network.NetworkPlugin {
|
||||
return probeNetworkPluginsWithVendorCNIDirPrefix(pluginDir, binDir, "")
|
||||
}
|
||||
|
||||
func getDefaultCNINetwork(pluginDir, binDir, vendorCNIDirPrefix string) (*cniNetwork, error) {
|
||||
if pluginDir == "" {
|
||||
pluginDir = DefaultNetDir
|
||||
}
|
||||
files, err := libcni.ConfFiles(pluginDir)
|
||||
switch {
|
||||
case err != nil:
|
||||
return nil, err
|
||||
case len(files) == 0:
|
||||
return nil, fmt.Errorf("No networks found in %s", pluginDir)
|
||||
}
|
||||
|
||||
sort.Strings(files)
|
||||
for _, confFile := range files {
|
||||
conf, err := libcni.ConfFromFile(confFile)
|
||||
if err != nil {
|
||||
glog.Warningf("Error loading CNI config file %s: %v", confFile, err)
|
||||
continue
|
||||
}
|
||||
// Search for vendor-specific plugins as well as default plugins in the CNI codebase.
|
||||
vendorDir := vendorCNIDir(vendorCNIDirPrefix, conf.Network.Type)
|
||||
cninet := &libcni.CNIConfig{
|
||||
Path: []string{binDir, vendorDir},
|
||||
}
|
||||
network := &cniNetwork{name: conf.Network.Name, NetworkConfig: conf, CNIConfig: cninet}
|
||||
return network, nil
|
||||
}
|
||||
return nil, fmt.Errorf("No valid networks found in %s", pluginDir)
|
||||
}
|
||||
|
||||
func vendorCNIDir(prefix, pluginType string) string {
|
||||
return fmt.Sprintf(VendorCNIDirTemplate, prefix, pluginType)
|
||||
}
|
||||
|
||||
func getLoNetwork(binDir, vendorDirPrefix string) *cniNetwork {
|
||||
loConfig, err := libcni.ConfFromBytes([]byte(`{
|
||||
"cniVersion": "0.1.0",
|
||||
"name": "cni-loopback",
|
||||
"type": "loopback"
|
||||
}`))
|
||||
if err != nil {
|
||||
// The hardcoded config above should always be valid and unit tests will
|
||||
// catch this
|
||||
panic(err)
|
||||
}
|
||||
cninet := &libcni.CNIConfig{
|
||||
Path: []string{vendorCNIDir(vendorDirPrefix, loConfig.Network.Type), binDir},
|
||||
}
|
||||
loNetwork := &cniNetwork{
|
||||
name: "lo",
|
||||
NetworkConfig: loConfig,
|
||||
CNIConfig: cninet,
|
||||
}
|
||||
|
||||
return loNetwork
|
||||
}
|
||||
|
||||
func (plugin *cniNetworkPlugin) Init(host network.Host, hairpinMode componentconfig.HairpinMode, nonMasqueradeCIDR string, mtu int) error {
|
||||
var err error
|
||||
plugin.nsenterPath, err = plugin.execer.LookPath("nsenter")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
plugin.host = host
|
||||
|
||||
// sync network config from pluginDir periodically to detect network config updates
|
||||
go wait.Forever(func() {
|
||||
plugin.syncNetworkConfig()
|
||||
}, 10*time.Second)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (plugin *cniNetworkPlugin) syncNetworkConfig() {
|
||||
network, err := getDefaultCNINetwork(plugin.pluginDir, plugin.binDir, plugin.vendorCNIDirPrefix)
|
||||
if err != nil {
|
||||
glog.Errorf("error updating cni config: %s", err)
|
||||
return
|
||||
}
|
||||
plugin.setDefaultNetwork(network)
|
||||
}
|
||||
|
||||
func (plugin *cniNetworkPlugin) getDefaultNetwork() *cniNetwork {
|
||||
plugin.RLock()
|
||||
defer plugin.RUnlock()
|
||||
return plugin.defaultNetwork
|
||||
}
|
||||
|
||||
func (plugin *cniNetworkPlugin) setDefaultNetwork(n *cniNetwork) {
|
||||
plugin.Lock()
|
||||
defer plugin.Unlock()
|
||||
plugin.defaultNetwork = n
|
||||
}
|
||||
|
||||
func (plugin *cniNetworkPlugin) checkInitialized() error {
|
||||
if plugin.getDefaultNetwork() == nil {
|
||||
return errors.New("cni config unintialized")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (plugin *cniNetworkPlugin) Name() string {
|
||||
return CNIPluginName
|
||||
}
|
||||
|
||||
func (plugin *cniNetworkPlugin) SetUpPod(namespace string, name string, id kubecontainer.ContainerID) error {
|
||||
if err := plugin.checkInitialized(); err != nil {
|
||||
return err
|
||||
}
|
||||
netnsPath, err := plugin.host.GetNetNS(id.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("CNI failed to retrieve network namespace path: %v", err)
|
||||
}
|
||||
|
||||
_, err = plugin.loNetwork.addToNetwork(name, namespace, id, netnsPath)
|
||||
if err != nil {
|
||||
glog.Errorf("Error while adding to cni lo network: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = plugin.getDefaultNetwork().addToNetwork(name, namespace, id, netnsPath)
|
||||
if err != nil {
|
||||
glog.Errorf("Error while adding to cni network: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (plugin *cniNetworkPlugin) TearDownPod(namespace string, name string, id kubecontainer.ContainerID) error {
|
||||
if err := plugin.checkInitialized(); err != nil {
|
||||
return err
|
||||
}
|
||||
netnsPath, err := plugin.host.GetNetNS(id.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("CNI failed to retrieve network namespace path: %v", err)
|
||||
}
|
||||
|
||||
return plugin.getDefaultNetwork().deleteFromNetwork(name, namespace, id, netnsPath)
|
||||
}
|
||||
|
||||
// TODO: Use the addToNetwork function to obtain the IP of the Pod. That will assume idempotent ADD call to the plugin.
|
||||
// Also fix the runtime's call to Status function to be done only in the case that the IP is lost, no need to do periodic calls
|
||||
func (plugin *cniNetworkPlugin) GetPodNetworkStatus(namespace string, name string, id kubecontainer.ContainerID) (*network.PodNetworkStatus, error) {
|
||||
netnsPath, err := plugin.host.GetNetNS(id.ID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("CNI failed to retrieve network namespace path: %v", err)
|
||||
}
|
||||
|
||||
ip, err := network.GetPodIP(plugin.execer, plugin.nsenterPath, netnsPath, network.DefaultInterfaceName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &network.PodNetworkStatus{IP: ip}, nil
|
||||
}
|
||||
|
||||
func (network *cniNetwork) addToNetwork(podName string, podNamespace string, podInfraContainerID kubecontainer.ContainerID, podNetnsPath string) (*cnitypes.Result, error) {
|
||||
rt, err := buildCNIRuntimeConf(podName, podNamespace, podInfraContainerID, podNetnsPath)
|
||||
if err != nil {
|
||||
glog.Errorf("Error adding network: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
netconf, cninet := network.NetworkConfig, network.CNIConfig
|
||||
glog.V(4).Infof("About to run with conf.Network.Type=%v", netconf.Network.Type)
|
||||
res, err := cninet.AddNetwork(netconf, rt)
|
||||
if err != nil {
|
||||
glog.Errorf("Error adding network: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (network *cniNetwork) deleteFromNetwork(podName string, podNamespace string, podInfraContainerID kubecontainer.ContainerID, podNetnsPath string) error {
|
||||
rt, err := buildCNIRuntimeConf(podName, podNamespace, podInfraContainerID, podNetnsPath)
|
||||
if err != nil {
|
||||
glog.Errorf("Error deleting network: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
netconf, cninet := network.NetworkConfig, network.CNIConfig
|
||||
glog.V(4).Infof("About to run with conf.Network.Type=%v", netconf.Network.Type)
|
||||
err = cninet.DelNetwork(netconf, rt)
|
||||
if err != nil {
|
||||
glog.Errorf("Error deleting network: %v", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildCNIRuntimeConf(podName string, podNs string, podInfraContainerID kubecontainer.ContainerID, podNetnsPath string) (*libcni.RuntimeConf, error) {
|
||||
glog.V(4).Infof("Got netns path %v", podNetnsPath)
|
||||
glog.V(4).Infof("Using netns path %v", podNs)
|
||||
|
||||
rt := &libcni.RuntimeConf{
|
||||
ContainerID: podInfraContainerID.ID,
|
||||
NetNS: podNetnsPath,
|
||||
IfName: network.DefaultInterfaceName,
|
||||
Args: [][2]string{
|
||||
{"IgnoreUnknown", "1"},
|
||||
{"K8S_POD_NAMESPACE", podNs},
|
||||
{"K8S_POD_NAME", podName},
|
||||
{"K8S_POD_INFRA_CONTAINER_ID", podInfraContainerID.ID},
|
||||
},
|
||||
}
|
||||
|
||||
return rt, nil
|
||||
}
|
||||
260
vendor/k8s.io/kubernetes/pkg/kubelet/network/cni/cni_test.go
generated
vendored
Normal file
260
vendor/k8s.io/kubernetes/pkg/kubelet/network/cni/cni_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
// +build linux
|
||||
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cni
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
"text/template"
|
||||
|
||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
||||
|
||||
cnitypes "github.com/containernetworking/cni/pkg/types"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/apis/componentconfig"
|
||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
|
||||
"k8s.io/kubernetes/pkg/kubelet/network"
|
||||
"k8s.io/kubernetes/pkg/kubelet/network/cni/testing"
|
||||
utilexec "k8s.io/kubernetes/pkg/util/exec"
|
||||
utiltesting "k8s.io/kubernetes/pkg/util/testing"
|
||||
)
|
||||
|
||||
func installPluginUnderTest(t *testing.T, testVendorCNIDirPrefix, testNetworkConfigPath, vendorName string, plugName string) {
|
||||
pluginDir := path.Join(testNetworkConfigPath, plugName)
|
||||
err := os.MkdirAll(pluginDir, 0777)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create plugin config dir: %v", err)
|
||||
}
|
||||
pluginConfig := path.Join(pluginDir, plugName+".conf")
|
||||
f, err := os.Create(pluginConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to install plugin")
|
||||
}
|
||||
networkConfig := fmt.Sprintf("{ \"name\": \"%s\", \"type\": \"%s\" }", plugName, vendorName)
|
||||
|
||||
_, err = f.WriteString(networkConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to write network config file (%v)", err)
|
||||
}
|
||||
f.Close()
|
||||
|
||||
vendorCNIDir := fmt.Sprintf(VendorCNIDirTemplate, testVendorCNIDirPrefix, vendorName)
|
||||
err = os.MkdirAll(vendorCNIDir, 0777)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create plugin dir: %v", err)
|
||||
}
|
||||
pluginExec := path.Join(vendorCNIDir, vendorName)
|
||||
f, err = os.Create(pluginExec)
|
||||
|
||||
const execScriptTempl = `#!/bin/bash
|
||||
read ignore
|
||||
env > {{.OutputEnv}}
|
||||
echo "%@" >> {{.OutputEnv}}
|
||||
export $(echo ${CNI_ARGS} | sed 's/;/ /g') &> /dev/null
|
||||
mkdir -p {{.OutputDir}} &> /dev/null
|
||||
echo -n "$CNI_COMMAND $CNI_NETNS $K8S_POD_NAMESPACE $K8S_POD_NAME $K8S_POD_INFRA_CONTAINER_ID" >& {{.OutputFile}}
|
||||
echo -n "{ \"ip4\": { \"ip\": \"10.1.0.23/24\" } }"
|
||||
`
|
||||
execTemplateData := &map[string]interface{}{
|
||||
"OutputFile": path.Join(pluginDir, plugName+".out"),
|
||||
"OutputEnv": path.Join(pluginDir, plugName+".env"),
|
||||
"OutputDir": pluginDir,
|
||||
}
|
||||
|
||||
tObj := template.Must(template.New("test").Parse(execScriptTempl))
|
||||
buf := &bytes.Buffer{}
|
||||
if err := tObj.Execute(buf, *execTemplateData); err != nil {
|
||||
t.Fatalf("Error in executing script template - %v", err)
|
||||
}
|
||||
execScript := buf.String()
|
||||
_, err = f.WriteString(execScript)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to write plugin exec - %v", err)
|
||||
}
|
||||
|
||||
err = f.Chmod(0777)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to set exec perms on plugin")
|
||||
}
|
||||
|
||||
f.Close()
|
||||
}
|
||||
|
||||
func tearDownPlugin(tmpDir string) {
|
||||
err := os.RemoveAll(tmpDir)
|
||||
if err != nil {
|
||||
fmt.Printf("Error in cleaning up test: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
type fakeNetworkHost struct {
|
||||
kubeClient clientset.Interface
|
||||
runtime kubecontainer.Runtime
|
||||
}
|
||||
|
||||
func NewFakeHost(kubeClient clientset.Interface, pods []*containertest.FakePod) *fakeNetworkHost {
|
||||
host := &fakeNetworkHost{
|
||||
kubeClient: kubeClient,
|
||||
runtime: &containertest.FakeRuntime{
|
||||
AllPodList: pods,
|
||||
},
|
||||
}
|
||||
return host
|
||||
}
|
||||
|
||||
func (fnh *fakeNetworkHost) GetPodByName(name, namespace string) (*v1.Pod, bool) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (fnh *fakeNetworkHost) GetKubeClient() clientset.Interface {
|
||||
return fnh.kubeClient
|
||||
}
|
||||
|
||||
func (fnh *fakeNetworkHost) GetRuntime() kubecontainer.Runtime {
|
||||
return fnh.runtime
|
||||
}
|
||||
|
||||
func (fnh *fakeNetworkHost) GetNetNS(containerID string) (string, error) {
|
||||
return fnh.GetRuntime().GetNetNS(kubecontainer.ContainerID{Type: "test", ID: containerID})
|
||||
}
|
||||
|
||||
func (fnh *fakeNetworkHost) SupportsLegacyFeatures() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func TestCNIPlugin(t *testing.T) {
|
||||
// install some random plugin
|
||||
pluginName := fmt.Sprintf("test%d", rand.Intn(1000))
|
||||
vendorName := fmt.Sprintf("test_vendor%d", rand.Intn(1000))
|
||||
|
||||
podIP := "10.0.0.2"
|
||||
podIPOutput := fmt.Sprintf("4: eth0 inet %s/24 scope global dynamic eth0\\ valid_lft forever preferred_lft forever", podIP)
|
||||
fakeCmds := []utilexec.FakeCommandAction{
|
||||
func(cmd string, args ...string) utilexec.Cmd {
|
||||
return utilexec.InitFakeCmd(&utilexec.FakeCmd{
|
||||
CombinedOutputScript: []utilexec.FakeCombinedOutputAction{
|
||||
func() ([]byte, error) {
|
||||
return []byte(podIPOutput), nil
|
||||
},
|
||||
},
|
||||
}, cmd, args...)
|
||||
},
|
||||
}
|
||||
|
||||
fexec := &utilexec.FakeExec{
|
||||
CommandScript: fakeCmds,
|
||||
LookPathFunc: func(file string) (string, error) {
|
||||
return fmt.Sprintf("/fake-bin/%s", file), nil
|
||||
},
|
||||
}
|
||||
|
||||
mockLoCNI := &mock_cni.MockCNI{}
|
||||
// TODO mock for the test plugin too
|
||||
|
||||
tmpDir := utiltesting.MkTmpdirOrDie("cni-test")
|
||||
testNetworkConfigPath := path.Join(tmpDir, "plugins", "net", "cni")
|
||||
testVendorCNIDirPrefix := tmpDir
|
||||
defer tearDownPlugin(tmpDir)
|
||||
installPluginUnderTest(t, testVendorCNIDirPrefix, testNetworkConfigPath, vendorName, pluginName)
|
||||
|
||||
containerID := kubecontainer.ContainerID{Type: "test", ID: "test_infra_container"}
|
||||
pods := []*containertest.FakePod{{
|
||||
Pod: &kubecontainer.Pod{
|
||||
Containers: []*kubecontainer.Container{
|
||||
{ID: containerID},
|
||||
},
|
||||
},
|
||||
NetnsPath: "/proc/12345/ns/net",
|
||||
}}
|
||||
|
||||
plugins := probeNetworkPluginsWithVendorCNIDirPrefix(path.Join(testNetworkConfigPath, pluginName), "", testVendorCNIDirPrefix)
|
||||
if len(plugins) != 1 {
|
||||
t.Fatalf("Expected only one network plugin, got %d", len(plugins))
|
||||
}
|
||||
if plugins[0].Name() != "cni" {
|
||||
t.Fatalf("Expected CNI network plugin, got %q", plugins[0].Name())
|
||||
}
|
||||
|
||||
cniPlugin, ok := plugins[0].(*cniNetworkPlugin)
|
||||
if !ok {
|
||||
t.Fatalf("Not a CNI network plugin!")
|
||||
}
|
||||
cniPlugin.execer = fexec
|
||||
cniPlugin.loNetwork.CNIConfig = mockLoCNI
|
||||
|
||||
mockLoCNI.On("AddNetwork", cniPlugin.loNetwork.NetworkConfig, mock.AnythingOfType("*libcni.RuntimeConf")).Return(&cnitypes.Result{IP4: &cnitypes.IPConfig{IP: net.IPNet{IP: []byte{127, 0, 0, 1}}}}, nil)
|
||||
|
||||
plug, err := network.InitNetworkPlugin(plugins, "cni", NewFakeHost(nil, pods), componentconfig.HairpinNone, "10.0.0.0/8", network.UseDefaultMTU)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to select the desired plugin: %v", err)
|
||||
}
|
||||
|
||||
// Set up the pod
|
||||
err = plug.SetUpPod("podNamespace", "podName", containerID)
|
||||
if err != nil {
|
||||
t.Errorf("Expected nil: %v", err)
|
||||
}
|
||||
outputEnv := path.Join(testNetworkConfigPath, pluginName, pluginName+".env")
|
||||
eo, eerr := ioutil.ReadFile(outputEnv)
|
||||
outputFile := path.Join(testNetworkConfigPath, pluginName, pluginName+".out")
|
||||
output, err := ioutil.ReadFile(outputFile)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to read output file %s: %v (env %s err %v)", outputFile, err, eo, eerr)
|
||||
}
|
||||
expectedOutput := "ADD /proc/12345/ns/net podNamespace podName test_infra_container"
|
||||
if string(output) != expectedOutput {
|
||||
t.Errorf("Mismatch in expected output for setup hook. Expected '%s', got '%s'", expectedOutput, string(output))
|
||||
}
|
||||
|
||||
// Get its IP address
|
||||
status, err := plug.GetPodNetworkStatus("podNamespace", "podName", containerID)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to read pod network status: %v", err)
|
||||
}
|
||||
if status.IP.String() != podIP {
|
||||
t.Errorf("Expected pod IP %q but got %q", podIP, status.IP.String())
|
||||
}
|
||||
|
||||
// Tear it down
|
||||
err = plug.TearDownPod("podNamespace", "podName", containerID)
|
||||
if err != nil {
|
||||
t.Errorf("Expected nil: %v", err)
|
||||
}
|
||||
output, err = ioutil.ReadFile(path.Join(testNetworkConfigPath, pluginName, pluginName+".out"))
|
||||
expectedOutput = "DEL /proc/12345/ns/net podNamespace podName test_infra_container"
|
||||
if string(output) != expectedOutput {
|
||||
t.Errorf("Mismatch in expected output for setup hook. Expected '%s', got '%s'", expectedOutput, string(output))
|
||||
}
|
||||
|
||||
mockLoCNI.AssertExpectations(t)
|
||||
}
|
||||
|
||||
func TestLoNetNonNil(t *testing.T) {
|
||||
if conf := getLoNetwork("", ""); conf == nil {
|
||||
t.Error("Expected non-nil lo network")
|
||||
}
|
||||
}
|
||||
22
vendor/k8s.io/kubernetes/pkg/kubelet/network/cni/testing/BUILD
generated
vendored
Normal file
22
vendor/k8s.io/kubernetes/pkg/kubelet/network/cni/testing/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["mock_cni.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//vendor:github.com/containernetworking/cni/libcni",
|
||||
"//vendor:github.com/containernetworking/cni/pkg/types",
|
||||
"//vendor:github.com/stretchr/testify/mock",
|
||||
],
|
||||
)
|
||||
39
vendor/k8s.io/kubernetes/pkg/kubelet/network/cni/testing/mock_cni.go
generated
vendored
Normal file
39
vendor/k8s.io/kubernetes/pkg/kubelet/network/cni/testing/mock_cni.go
generated
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// mock_cni is a mock of the `libcni.CNI` interface. It's a handwritten mock
|
||||
// because there are only two functions to deal with.
|
||||
package mock_cni
|
||||
|
||||
import (
|
||||
"github.com/containernetworking/cni/libcni"
|
||||
"github.com/containernetworking/cni/pkg/types"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
type MockCNI struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
func (m *MockCNI) AddNetwork(net *libcni.NetworkConfig, rt *libcni.RuntimeConf) (*types.Result, error) {
|
||||
args := m.Called(net, rt)
|
||||
return args.Get(0).(*types.Result), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *MockCNI) DelNetwork(net *libcni.NetworkConfig, rt *libcni.RuntimeConf) error {
|
||||
args := m.Called(net, rt)
|
||||
return args.Error(0)
|
||||
}
|
||||
43
vendor/k8s.io/kubernetes/pkg/kubelet/network/exec/BUILD
generated
vendored
Normal file
43
vendor/k8s.io/kubernetes/pkg/kubelet/network/exec/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"exec.go",
|
||||
"exec_unix.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/apis/componentconfig:go_default_library",
|
||||
"//pkg/apis/meta/v1:go_default_library",
|
||||
"//pkg/kubelet/container:go_default_library",
|
||||
"//pkg/kubelet/network:go_default_library",
|
||||
"//pkg/util/exec:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["exec_test.go"],
|
||||
library = "go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/apis/componentconfig:go_default_library",
|
||||
"//pkg/kubelet/container:go_default_library",
|
||||
"//pkg/kubelet/network:go_default_library",
|
||||
"//pkg/kubelet/network/testing:go_default_library",
|
||||
"//pkg/util/sets:go_default_library",
|
||||
"//pkg/util/testing:go_default_library",
|
||||
],
|
||||
)
|
||||
203
vendor/k8s.io/kubernetes/pkg/kubelet/network/exec/exec.go
generated
vendored
Normal file
203
vendor/k8s.io/kubernetes/pkg/kubelet/network/exec/exec.go
generated
vendored
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package exec scans and loads networking plugins that are installed
|
||||
// under /usr/libexec/kubernetes/kubelet-plugins/net/exec/
|
||||
// The layout convention for a plugin is:
|
||||
// plugin-name/ (plugins have to be directories first)
|
||||
// plugin-name/plugin-name (executable that will be called out, see Vendoring Note for more nuances)
|
||||
// plugin-name/<other-files>
|
||||
// where, 'executable' has the following requirements:
|
||||
// - should have exec permissions
|
||||
// - should give non-zero exit code on failure, and zero on success
|
||||
// - the arguments will be <action> <pod_namespace> <pod_name> <docker_id_of_infra_container>
|
||||
// whereupon, <action> will be one of:
|
||||
// - init, called when the kubelet loads the plugin
|
||||
// - setup, called after the infra container of a pod is
|
||||
// created, but before other containers of the pod are created
|
||||
// - teardown, called before the pod infra container is killed
|
||||
// - status, called at regular intervals and is supposed to return a json
|
||||
// formatted output indicating the pod's IPAddress(v4/v6). An empty string value or an erroneous output
|
||||
// will mean the container runtime (docker) will be asked for the PodIP
|
||||
// e.g. {
|
||||
// "apiVersion" : "v1beta1",
|
||||
// "kind" : "PodNetworkStatus",
|
||||
// "ip" : "10.20.30.40"
|
||||
// }
|
||||
// The fields "apiVersion" and "kind" are optional in version v1beta1
|
||||
// As the executables are called, the file-descriptors stdin, stdout, stderr
|
||||
// remain open. The combined output of stdout/stderr is captured and logged.
|
||||
//
|
||||
// Note: If the pod infra container self-terminates (e.g. crashes or is killed),
|
||||
// the entire pod lifecycle will be restarted, but teardown will not be called.
|
||||
//
|
||||
// Vendoring Note:
|
||||
// Plugin Names can be vendored also. Use '~' as the escaped name for plugin directories.
|
||||
// And expect command line argument to call vendored plugins as 'vendor/pluginName'
|
||||
// e.g. pluginName = mysdn
|
||||
// vendorname = mycompany
|
||||
// then, plugin layout should be
|
||||
// mycompany~mysdn/
|
||||
// mycompany~mysdn/mysdn (this becomes the executable)
|
||||
// mycompany~mysdn/<other-files>
|
||||
// and, call the kubelet with '--network-plugin=mycompany/mysdn'
|
||||
package exec
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kubernetes/pkg/apis/componentconfig"
|
||||
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
|
||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
"k8s.io/kubernetes/pkg/kubelet/network"
|
||||
utilexec "k8s.io/kubernetes/pkg/util/exec"
|
||||
)
|
||||
|
||||
type execNetworkPlugin struct {
|
||||
network.NoopNetworkPlugin
|
||||
|
||||
execName string
|
||||
execPath string
|
||||
host network.Host
|
||||
}
|
||||
|
||||
const (
|
||||
initCmd = "init"
|
||||
setUpCmd = "setup"
|
||||
tearDownCmd = "teardown"
|
||||
statusCmd = "status"
|
||||
defaultDir = "/usr/libexec/kubernetes/kubelet-plugins/net/exec/"
|
||||
)
|
||||
|
||||
func ProbeNetworkPlugins(pluginDir string) []network.NetworkPlugin {
|
||||
execPlugins := []network.NetworkPlugin{}
|
||||
|
||||
if pluginDir == "" {
|
||||
pluginDir = defaultDir
|
||||
}
|
||||
|
||||
files, _ := ioutil.ReadDir(pluginDir)
|
||||
for _, f := range files {
|
||||
// only directories are counted as plugins
|
||||
// and pluginDir/dirname/dirname should be an executable
|
||||
// unless dirname contains '~' for escaping namespace
|
||||
// e.g. dirname = vendor~ipvlan
|
||||
// then, executable will be pluginDir/dirname/ipvlan
|
||||
if f.IsDir() {
|
||||
execPath := path.Join(pluginDir, f.Name())
|
||||
execPlugins = append(execPlugins, &execNetworkPlugin{execName: network.UnescapePluginName(f.Name()), execPath: execPath})
|
||||
}
|
||||
}
|
||||
return execPlugins
|
||||
}
|
||||
|
||||
func (plugin *execNetworkPlugin) Init(host network.Host, hairpinMode componentconfig.HairpinMode, nonMasqueradeCIDR string, mtu int) error {
|
||||
err := plugin.validate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
plugin.host = host
|
||||
// call the init script
|
||||
out, err := utilexec.New().Command(plugin.getExecutable(), initCmd).CombinedOutput()
|
||||
if err != nil {
|
||||
glog.V(5).Infof("Init 'exec' network plugin output: %s, %v", string(out), err)
|
||||
} else {
|
||||
glog.V(5).Infof("Init 'exec' network plugin output: %s", string(out))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (plugin *execNetworkPlugin) getExecutable() string {
|
||||
parts := strings.Split(plugin.execName, "/")
|
||||
execName := parts[len(parts)-1]
|
||||
return path.Join(plugin.execPath, execName)
|
||||
}
|
||||
|
||||
func (plugin *execNetworkPlugin) Name() string {
|
||||
return plugin.execName
|
||||
}
|
||||
|
||||
func (plugin *execNetworkPlugin) validate() error {
|
||||
if !isExecutable(plugin.getExecutable()) {
|
||||
errStr := fmt.Sprintf("Invalid exec plugin. Executable '%s' does not have correct permissions.", plugin.execName)
|
||||
return errors.New(errStr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (plugin *execNetworkPlugin) SetUpPod(namespace string, name string, id kubecontainer.ContainerID) error {
|
||||
out, err := utilexec.New().Command(plugin.getExecutable(), setUpCmd, namespace, name, id.ID).CombinedOutput()
|
||||
if err != nil {
|
||||
glog.V(5).Infof("SetUpPod 'exec' network plugin output: %s, %v", string(out), err)
|
||||
} else {
|
||||
glog.V(5).Infof("SetUpPod 'exec' network plugin output: %s", string(out))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (plugin *execNetworkPlugin) TearDownPod(namespace string, name string, id kubecontainer.ContainerID) error {
|
||||
out, err := utilexec.New().Command(plugin.getExecutable(), tearDownCmd, namespace, name, id.ID).CombinedOutput()
|
||||
if err != nil {
|
||||
glog.V(5).Infof("TearDownPod 'exec' network plugin output: %s, %v", string(out), err)
|
||||
} else {
|
||||
glog.V(5).Infof("TearDownPod 'exec' network plugin output: %s", string(out))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (plugin *execNetworkPlugin) GetPodNetworkStatus(namespace string, name string, id kubecontainer.ContainerID) (*network.PodNetworkStatus, error) {
|
||||
out, err := utilexec.New().Command(plugin.getExecutable(), statusCmd, namespace, name, id.ID).CombinedOutput()
|
||||
if err != nil {
|
||||
glog.V(5).Infof("Status 'exec' network plugin output: %s, %v", string(out), err)
|
||||
return nil, err
|
||||
} else {
|
||||
glog.V(5).Infof("Status 'exec' network plugin output: %s", string(out))
|
||||
}
|
||||
if string(out) == "" {
|
||||
return nil, nil
|
||||
}
|
||||
findVersion := struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
}{}
|
||||
err = json.Unmarshal(out, &findVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// check kind and version
|
||||
if findVersion.Kind != "" && findVersion.Kind != "PodNetworkStatus" {
|
||||
errStr := fmt.Sprintf("Invalid 'kind' returned in network status for pod '%s'. Valid value is 'PodNetworkStatus', got '%s'.", name, findVersion.Kind)
|
||||
return nil, errors.New(errStr)
|
||||
}
|
||||
switch findVersion.APIVersion {
|
||||
case "":
|
||||
fallthrough
|
||||
case "v1beta1":
|
||||
networkStatus := &network.PodNetworkStatus{}
|
||||
err = json.Unmarshal(out, networkStatus)
|
||||
return networkStatus, err
|
||||
}
|
||||
errStr := fmt.Sprintf("Unknown version '%s' in network status for pod '%s'.", findVersion.APIVersion, name)
|
||||
return nil, errors.New(errStr)
|
||||
}
|
||||
341
vendor/k8s.io/kubernetes/pkg/kubelet/network/exec/exec_test.go
generated
vendored
Normal file
341
vendor/k8s.io/kubernetes/pkg/kubelet/network/exec/exec_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,341 @@
|
|||
// +build linux
|
||||
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package exec
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path"
|
||||
"sync"
|
||||
"testing"
|
||||
"text/template"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/componentconfig"
|
||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
"k8s.io/kubernetes/pkg/kubelet/network"
|
||||
nettest "k8s.io/kubernetes/pkg/kubelet/network/testing"
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
utiltesting "k8s.io/kubernetes/pkg/util/testing"
|
||||
)
|
||||
|
||||
func tmpDirOrDie() string {
|
||||
dir, err := utiltesting.MkTmpdir("exec-test")
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("error creating tmp dir: %v", err))
|
||||
}
|
||||
return path.Join(dir, "fake", "plugins", "net")
|
||||
}
|
||||
|
||||
var lock sync.Mutex
|
||||
var namesInUse = sets.NewString()
|
||||
|
||||
func selectName() string {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
for {
|
||||
pluginName := fmt.Sprintf("test%d", rand.Intn(1000))
|
||||
if !namesInUse.Has(pluginName) {
|
||||
namesInUse.Insert(pluginName)
|
||||
return pluginName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func releaseName(name string) {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
namesInUse.Delete(name)
|
||||
}
|
||||
|
||||
func installPluginUnderTest(t *testing.T, vendorName, testPluginPath, plugName string, execTemplateData *map[string]interface{}) {
|
||||
vendoredName := plugName
|
||||
if vendorName != "" {
|
||||
vendoredName = fmt.Sprintf("%s~%s", vendorName, plugName)
|
||||
}
|
||||
pluginDir := path.Join(testPluginPath, vendoredName)
|
||||
err := os.MkdirAll(pluginDir, 0777)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to create plugin dir %q: %v", pluginDir, err)
|
||||
}
|
||||
pluginExec := path.Join(pluginDir, plugName)
|
||||
f, err := os.Create(pluginExec)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to install plugin %q: %v", pluginExec, err)
|
||||
}
|
||||
defer f.Close()
|
||||
err = f.Chmod(0777)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to set exec perms on plugin %q: %v", pluginExec, err)
|
||||
}
|
||||
const execScriptTempl = `#!/bin/bash
|
||||
|
||||
# If status hook is called print the expected json to stdout
|
||||
if [ "$1" == "status" ]; then
|
||||
echo -n '{
|
||||
"ip" : "{{.IPAddress}}"
|
||||
}'
|
||||
fi
|
||||
|
||||
# Direct the arguments to a file to be tested against later
|
||||
echo -n "$@" &> {{.OutputFile}}
|
||||
`
|
||||
if execTemplateData == nil {
|
||||
execTemplateData = &map[string]interface{}{
|
||||
"IPAddress": "10.20.30.40",
|
||||
"OutputFile": path.Join(pluginDir, plugName+".out"),
|
||||
}
|
||||
}
|
||||
|
||||
tObj := template.Must(template.New("test").Parse(execScriptTempl))
|
||||
buf := &bytes.Buffer{}
|
||||
if err := tObj.Execute(buf, *execTemplateData); err != nil {
|
||||
t.Errorf("Error in executing script template: %v", err)
|
||||
}
|
||||
execScript := buf.String()
|
||||
_, err = f.WriteString(execScript)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to write plugin %q: %v", pluginExec, err)
|
||||
}
|
||||
}
|
||||
|
||||
func tearDownPlugin(testPluginPath string) {
|
||||
err := os.RemoveAll(testPluginPath)
|
||||
if err != nil {
|
||||
fmt.Printf("Error in cleaning up test: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSelectPlugin(t *testing.T) {
|
||||
// The temp dir where test plugins will be stored.
|
||||
testPluginPath := tmpDirOrDie()
|
||||
|
||||
// install some random plugin under testPluginPath
|
||||
pluginName := selectName()
|
||||
defer tearDownPlugin(testPluginPath)
|
||||
defer releaseName(pluginName)
|
||||
|
||||
installPluginUnderTest(t, "", testPluginPath, pluginName, nil)
|
||||
|
||||
plug, err := network.InitNetworkPlugin(ProbeNetworkPlugins(testPluginPath), pluginName, nettest.NewFakeHost(nil), componentconfig.HairpinNone, "10.0.0.0/8", network.UseDefaultMTU)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to select the desired plugin: %v", err)
|
||||
}
|
||||
if plug.Name() != pluginName {
|
||||
t.Errorf("Wrong plugin selected, chose %s, got %s\n", pluginName, plug.Name())
|
||||
}
|
||||
}
|
||||
|
||||
func TestSelectVendoredPlugin(t *testing.T) {
|
||||
// The temp dir where test plugins will be stored.
|
||||
testPluginPath := tmpDirOrDie()
|
||||
|
||||
// install some random plugin under testPluginPath
|
||||
pluginName := selectName()
|
||||
defer tearDownPlugin(testPluginPath)
|
||||
defer releaseName(pluginName)
|
||||
|
||||
vendor := "mycompany"
|
||||
installPluginUnderTest(t, vendor, testPluginPath, pluginName, nil)
|
||||
|
||||
vendoredPluginName := fmt.Sprintf("%s/%s", vendor, pluginName)
|
||||
plug, err := network.InitNetworkPlugin(ProbeNetworkPlugins(testPluginPath), vendoredPluginName, nettest.NewFakeHost(nil), componentconfig.HairpinNone, "10.0.0.0/8", network.UseDefaultMTU)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to select the desired plugin: %v", err)
|
||||
}
|
||||
if plug.Name() != vendoredPluginName {
|
||||
t.Errorf("Wrong plugin selected, chose %s, got %s\n", vendoredPluginName, plug.Name())
|
||||
}
|
||||
}
|
||||
|
||||
func TestSelectWrongPlugin(t *testing.T) {
|
||||
// The temp dir where test plugins will be stored.
|
||||
testPluginPath := tmpDirOrDie()
|
||||
|
||||
// install some random plugin under testPluginPath
|
||||
pluginName := selectName()
|
||||
defer tearDownPlugin(testPluginPath)
|
||||
defer releaseName(pluginName)
|
||||
|
||||
installPluginUnderTest(t, "", testPluginPath, pluginName, nil)
|
||||
|
||||
wrongPlugin := "abcd"
|
||||
plug, err := network.InitNetworkPlugin(ProbeNetworkPlugins(testPluginPath), wrongPlugin, nettest.NewFakeHost(nil), componentconfig.HairpinNone, "10.0.0.0/8", network.UseDefaultMTU)
|
||||
if plug != nil || err == nil {
|
||||
t.Errorf("Expected to see an error. Wrong plugin selected.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPluginValidation(t *testing.T) {
|
||||
// The temp dir where test plugins will be stored.
|
||||
testPluginPath := tmpDirOrDie()
|
||||
|
||||
// install some random plugin under testPluginPath
|
||||
pluginName := selectName()
|
||||
defer tearDownPlugin(testPluginPath)
|
||||
defer releaseName(pluginName)
|
||||
|
||||
installPluginUnderTest(t, "", testPluginPath, pluginName, nil)
|
||||
|
||||
// modify the perms of the pluginExecutable
|
||||
f, err := os.Open(path.Join(testPluginPath, pluginName, pluginName))
|
||||
if err != nil {
|
||||
t.Errorf("Nil value expected.")
|
||||
}
|
||||
err = f.Chmod(0444)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to set perms on plugin exec")
|
||||
}
|
||||
f.Close()
|
||||
|
||||
_, err = network.InitNetworkPlugin(ProbeNetworkPlugins(testPluginPath), pluginName, nettest.NewFakeHost(nil), componentconfig.HairpinNone, "10.0.0.0/8", network.UseDefaultMTU)
|
||||
if err == nil {
|
||||
// we expected an error here because validation would have failed
|
||||
t.Errorf("Expected non-nil value.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPluginSetupHook(t *testing.T) {
|
||||
// The temp dir where test plugins will be stored.
|
||||
testPluginPath := tmpDirOrDie()
|
||||
|
||||
// install some random plugin under testPluginPath
|
||||
pluginName := selectName()
|
||||
defer tearDownPlugin(testPluginPath)
|
||||
defer releaseName(pluginName)
|
||||
|
||||
installPluginUnderTest(t, "", testPluginPath, pluginName, nil)
|
||||
|
||||
plug, err := network.InitNetworkPlugin(ProbeNetworkPlugins(testPluginPath), pluginName, nettest.NewFakeHost(nil), componentconfig.HairpinNone, "10.0.0.0/8", network.UseDefaultMTU)
|
||||
|
||||
err = plug.SetUpPod("podNamespace", "podName", kubecontainer.ContainerID{Type: "docker", ID: "dockerid2345"})
|
||||
if err != nil {
|
||||
t.Errorf("Expected nil: %v", err)
|
||||
}
|
||||
// check output of setup hook
|
||||
output, err := ioutil.ReadFile(path.Join(testPluginPath, pluginName, pluginName+".out"))
|
||||
if err != nil {
|
||||
t.Errorf("Expected nil")
|
||||
}
|
||||
expectedOutput := "setup podNamespace podName dockerid2345"
|
||||
if string(output) != expectedOutput {
|
||||
t.Errorf("Mismatch in expected output for setup hook. Expected '%s', got '%s'", expectedOutput, string(output))
|
||||
}
|
||||
}
|
||||
|
||||
func TestPluginTearDownHook(t *testing.T) {
|
||||
// The temp dir where test plugins will be stored.
|
||||
testPluginPath := tmpDirOrDie()
|
||||
|
||||
// install some random plugin under testPluginPath
|
||||
pluginName := selectName()
|
||||
defer tearDownPlugin(testPluginPath)
|
||||
defer releaseName(pluginName)
|
||||
|
||||
installPluginUnderTest(t, "", testPluginPath, pluginName, nil)
|
||||
|
||||
plug, err := network.InitNetworkPlugin(ProbeNetworkPlugins(testPluginPath), pluginName, nettest.NewFakeHost(nil), componentconfig.HairpinNone, "10.0.0.0/8", network.UseDefaultMTU)
|
||||
|
||||
err = plug.TearDownPod("podNamespace", "podName", kubecontainer.ContainerID{Type: "docker", ID: "dockerid2345"})
|
||||
if err != nil {
|
||||
t.Errorf("Expected nil")
|
||||
}
|
||||
// check output of setup hook
|
||||
output, err := ioutil.ReadFile(path.Join(testPluginPath, pluginName, pluginName+".out"))
|
||||
if err != nil {
|
||||
t.Errorf("Expected nil")
|
||||
}
|
||||
expectedOutput := "teardown podNamespace podName dockerid2345"
|
||||
if string(output) != expectedOutput {
|
||||
t.Errorf("Mismatch in expected output for teardown hook. Expected '%s', got '%s'", expectedOutput, string(output))
|
||||
}
|
||||
}
|
||||
|
||||
func TestPluginStatusHook(t *testing.T) {
|
||||
// The temp dir where test plugins will be stored.
|
||||
testPluginPath := tmpDirOrDie()
|
||||
|
||||
// install some random plugin under testPluginPath
|
||||
pluginName := selectName()
|
||||
defer tearDownPlugin(testPluginPath)
|
||||
defer releaseName(pluginName)
|
||||
|
||||
installPluginUnderTest(t, "", testPluginPath, pluginName, nil)
|
||||
|
||||
plug, err := network.InitNetworkPlugin(ProbeNetworkPlugins(testPluginPath), pluginName, nettest.NewFakeHost(nil), componentconfig.HairpinNone, "10.0.0.0/8", network.UseDefaultMTU)
|
||||
|
||||
ip, err := plug.GetPodNetworkStatus("namespace", "name", kubecontainer.ContainerID{Type: "docker", ID: "dockerid2345"})
|
||||
if err != nil {
|
||||
t.Errorf("Expected nil got %v", err)
|
||||
}
|
||||
// check output of status hook
|
||||
output, err := ioutil.ReadFile(path.Join(testPluginPath, pluginName, pluginName+".out"))
|
||||
if err != nil {
|
||||
t.Errorf("Expected nil")
|
||||
}
|
||||
expectedOutput := "status namespace name dockerid2345"
|
||||
if string(output) != expectedOutput {
|
||||
t.Errorf("Mismatch in expected output for status hook. Expected '%s', got '%s'", expectedOutput, string(output))
|
||||
}
|
||||
if ip.IP.String() != "10.20.30.40" {
|
||||
t.Errorf("Mismatch in expected output for status hook. Expected '10.20.30.40', got '%s'", ip.IP.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestPluginStatusHookIPv6(t *testing.T) {
|
||||
// The temp dir where test plugins will be stored.
|
||||
testPluginPath := tmpDirOrDie()
|
||||
|
||||
// install some random plugin under testPluginPath
|
||||
pluginName := selectName()
|
||||
defer tearDownPlugin(testPluginPath)
|
||||
defer releaseName(pluginName)
|
||||
|
||||
pluginDir := path.Join(testPluginPath, pluginName)
|
||||
execTemplate := &map[string]interface{}{
|
||||
"IPAddress": "fe80::e2cb:4eff:fef9:6710",
|
||||
"OutputFile": path.Join(pluginDir, pluginName+".out"),
|
||||
}
|
||||
installPluginUnderTest(t, "", testPluginPath, pluginName, execTemplate)
|
||||
|
||||
plug, err := network.InitNetworkPlugin(ProbeNetworkPlugins(testPluginPath), pluginName, nettest.NewFakeHost(nil), componentconfig.HairpinNone, "10.0.0.0/8", network.UseDefaultMTU)
|
||||
if err != nil {
|
||||
t.Errorf("InitNetworkPlugin() failed: %v", err)
|
||||
}
|
||||
|
||||
ip, err := plug.GetPodNetworkStatus("namespace", "name", kubecontainer.ContainerID{Type: "docker", ID: "dockerid2345"})
|
||||
if err != nil {
|
||||
t.Errorf("Status() failed: %v", err)
|
||||
}
|
||||
// check output of status hook
|
||||
outPath := path.Join(testPluginPath, pluginName, pluginName+".out")
|
||||
output, err := ioutil.ReadFile(outPath)
|
||||
if err != nil {
|
||||
t.Errorf("ReadFile(%q) failed: %v", outPath, err)
|
||||
}
|
||||
expectedOutput := "status namespace name dockerid2345"
|
||||
if string(output) != expectedOutput {
|
||||
t.Errorf("Mismatch in expected output for status hook. Expected %q, got %q", expectedOutput, string(output))
|
||||
}
|
||||
if ip.IP.String() != "fe80::e2cb:4eff:fef9:6710" {
|
||||
t.Errorf("Mismatch in expected output for status hook. Expected 'fe80::e2cb:4eff:fef9:6710', got '%s'", ip.IP.String())
|
||||
}
|
||||
}
|
||||
27
vendor/k8s.io/kubernetes/pkg/kubelet/network/exec/exec_unix.go
generated
vendored
Normal file
27
vendor/k8s.io/kubernetes/pkg/kubelet/network/exec/exec_unix.go
generated
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// +build !windows
|
||||
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package exec
|
||||
|
||||
import "syscall"
|
||||
|
||||
const X_OK = 0x1
|
||||
|
||||
func isExecutable(path string) bool {
|
||||
return syscall.Access(path, X_OK) == nil
|
||||
}
|
||||
23
vendor/k8s.io/kubernetes/pkg/kubelet/network/exec/exec_unsupported.go
generated
vendored
Normal file
23
vendor/k8s.io/kubernetes/pkg/kubelet/network/exec/exec_unsupported.go
generated
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
// +build windows
|
||||
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package exec
|
||||
|
||||
func isExecutable(path string) bool {
|
||||
return false
|
||||
}
|
||||
29
vendor/k8s.io/kubernetes/pkg/kubelet/network/hairpin/BUILD
generated
vendored
Normal file
29
vendor/k8s.io/kubernetes/pkg/kubelet/network/hairpin/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["hairpin.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/util/exec:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["hairpin_test.go"],
|
||||
library = "go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = ["//pkg/util/exec:go_default_library"],
|
||||
)
|
||||
122
vendor/k8s.io/kubernetes/pkg/kubelet/network/hairpin/hairpin.go
generated
vendored
Normal file
122
vendor/k8s.io/kubernetes/pkg/kubelet/network/hairpin/hairpin.go
generated
vendored
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package hairpin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kubernetes/pkg/util/exec"
|
||||
)
|
||||
|
||||
const (
|
||||
sysfsNetPath = "/sys/devices/virtual/net"
|
||||
brportRelativePath = "brport"
|
||||
hairpinModeRelativePath = "hairpin_mode"
|
||||
hairpinEnable = "1"
|
||||
)
|
||||
|
||||
var (
|
||||
ethtoolOutputRegex = regexp.MustCompile("peer_ifindex: (\\d+)")
|
||||
)
|
||||
|
||||
func SetUpContainerPid(containerPid int, containerInterfaceName string) error {
|
||||
pidStr := fmt.Sprintf("%d", containerPid)
|
||||
nsenterArgs := []string{"-t", pidStr, "-n"}
|
||||
return setUpContainerInternal(containerInterfaceName, pidStr, nsenterArgs)
|
||||
}
|
||||
|
||||
func SetUpContainerPath(netnsPath string, containerInterfaceName string) error {
|
||||
if netnsPath[0] != '/' {
|
||||
return fmt.Errorf("netnsPath path '%s' was invalid", netnsPath)
|
||||
}
|
||||
nsenterArgs := []string{"-n", netnsPath}
|
||||
return setUpContainerInternal(containerInterfaceName, netnsPath, nsenterArgs)
|
||||
}
|
||||
|
||||
func setUpContainerInternal(containerInterfaceName, containerDesc string, nsenterArgs []string) error {
|
||||
e := exec.New()
|
||||
hostIfName, err := findPairInterfaceOfContainerInterface(e, containerInterfaceName, containerDesc, nsenterArgs)
|
||||
if err != nil {
|
||||
glog.Infof("Unable to find pair interface, setting up all interfaces: %v", err)
|
||||
return setUpAllInterfaces()
|
||||
}
|
||||
return setUpInterface(hostIfName)
|
||||
}
|
||||
|
||||
func findPairInterfaceOfContainerInterface(e exec.Interface, containerInterfaceName, containerDesc string, nsenterArgs []string) (string, error) {
|
||||
nsenterPath, err := e.LookPath("nsenter")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
ethtoolPath, err := e.LookPath("ethtool")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
nsenterArgs = append(nsenterArgs, "-F", "--", ethtoolPath, "--statistics", containerInterfaceName)
|
||||
output, err := e.Command(nsenterPath, nsenterArgs...).CombinedOutput()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Unable to query interface %s of container %s: %v: %s", containerInterfaceName, containerDesc, err, string(output))
|
||||
}
|
||||
// look for peer_ifindex
|
||||
match := ethtoolOutputRegex.FindSubmatch(output)
|
||||
if match == nil {
|
||||
return "", fmt.Errorf("No peer_ifindex in interface statistics for %s of container %s", containerInterfaceName, containerDesc)
|
||||
}
|
||||
peerIfIndex, err := strconv.Atoi(string(match[1]))
|
||||
if err != nil { // seems impossible (\d+ not numeric)
|
||||
return "", fmt.Errorf("peer_ifindex wasn't numeric: %s: %v", match[1], err)
|
||||
}
|
||||
iface, err := net.InterfaceByIndex(peerIfIndex)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return iface.Name, nil
|
||||
}
|
||||
|
||||
func setUpAllInterfaces() error {
|
||||
interfaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, netIf := range interfaces {
|
||||
setUpInterface(netIf.Name) // ignore errors
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setUpInterface(ifName string) error {
|
||||
glog.V(3).Infof("Enabling hairpin on interface %s", ifName)
|
||||
ifPath := path.Join(sysfsNetPath, ifName)
|
||||
if _, err := os.Stat(ifPath); err != nil {
|
||||
return err
|
||||
}
|
||||
brportPath := path.Join(ifPath, brportRelativePath)
|
||||
if _, err := os.Stat(brportPath); err != nil && os.IsNotExist(err) {
|
||||
// Device is not on a bridge, so doesn't need hairpin mode
|
||||
return nil
|
||||
}
|
||||
hairpinModeFile := path.Join(brportPath, hairpinModeRelativePath)
|
||||
return ioutil.WriteFile(hairpinModeFile, []byte(hairpinEnable), 0644)
|
||||
}
|
||||
108
vendor/k8s.io/kubernetes/pkg/kubelet/network/hairpin/hairpin_test.go
generated
vendored
Normal file
108
vendor/k8s.io/kubernetes/pkg/kubelet/network/hairpin/hairpin_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package hairpin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/util/exec"
|
||||
)
|
||||
|
||||
func TestFindPairInterfaceOfContainerInterface(t *testing.T) {
|
||||
// there should be at least "lo" on any system
|
||||
interfaces, _ := net.Interfaces()
|
||||
validOutput := fmt.Sprintf("garbage\n peer_ifindex: %d", interfaces[0].Index)
|
||||
invalidOutput := fmt.Sprintf("garbage\n unknown: %d", interfaces[0].Index)
|
||||
|
||||
tests := []struct {
|
||||
output string
|
||||
err error
|
||||
expectedName string
|
||||
expectErr bool
|
||||
}{
|
||||
{
|
||||
output: validOutput,
|
||||
expectedName: interfaces[0].Name,
|
||||
},
|
||||
{
|
||||
output: invalidOutput,
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
output: validOutput,
|
||||
err: errors.New("error"),
|
||||
expectErr: true,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
func() ([]byte, error) { return []byte(test.output), test.err },
|
||||
},
|
||||
}
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
func(cmd string, args ...string) exec.Cmd {
|
||||
return exec.InitFakeCmd(&fcmd, cmd, args...)
|
||||
},
|
||||
},
|
||||
LookPathFunc: func(file string) (string, error) {
|
||||
return fmt.Sprintf("/fake-bin/%s", file), nil
|
||||
},
|
||||
}
|
||||
nsenterArgs := []string{"-t", "123", "-n"}
|
||||
name, err := findPairInterfaceOfContainerInterface(&fexec, "eth0", "123", nsenterArgs)
|
||||
if test.expectErr {
|
||||
if err == nil {
|
||||
t.Errorf("unexpected non-error")
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
if name != test.expectedName {
|
||||
t.Errorf("unexpected name: %s (expected: %s)", name, test.expectedName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetUpInterfaceNonExistent(t *testing.T) {
|
||||
err := setUpInterface("non-existent")
|
||||
if err == nil {
|
||||
t.Errorf("unexpected non-error")
|
||||
}
|
||||
deviceDir := fmt.Sprintf("%s/%s", sysfsNetPath, "non-existent")
|
||||
if !strings.Contains(fmt.Sprintf("%v", err), deviceDir) {
|
||||
t.Errorf("should have tried to open %s", deviceDir)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetUpInterfaceNotBridged(t *testing.T) {
|
||||
err := setUpInterface("lo")
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
t.Skipf("'lo' device does not exist??? (%v)", err)
|
||||
}
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
41
vendor/k8s.io/kubernetes/pkg/kubelet/network/hostport/BUILD
generated
vendored
Normal file
41
vendor/k8s.io/kubernetes/pkg/kubelet/network/hostport/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"fake_iptables.go",
|
||||
"hostport.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/kubelet/container:go_default_library",
|
||||
"//pkg/proxy/iptables:go_default_library",
|
||||
"//pkg/util/dbus:go_default_library",
|
||||
"//pkg/util/exec:go_default_library",
|
||||
"//pkg/util/iptables:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["hostport_test.go"],
|
||||
library = "go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/kubelet/container:go_default_library",
|
||||
"//pkg/util/iptables:go_default_library",
|
||||
],
|
||||
)
|
||||
335
vendor/k8s.io/kubernetes/pkg/kubelet/network/hostport/fake_iptables.go
generated
vendored
Normal file
335
vendor/k8s.io/kubernetes/pkg/kubelet/network/hostport/fake_iptables.go
generated
vendored
Normal file
|
|
@ -0,0 +1,335 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package hostport
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
utiliptables "k8s.io/kubernetes/pkg/util/iptables"
|
||||
)
|
||||
|
||||
type fakeChain struct {
|
||||
name utiliptables.Chain
|
||||
rules []string
|
||||
}
|
||||
|
||||
type fakeTable struct {
|
||||
name utiliptables.Table
|
||||
chains map[string]*fakeChain
|
||||
}
|
||||
|
||||
type fakeIPTables struct {
|
||||
tables map[string]*fakeTable
|
||||
}
|
||||
|
||||
func NewFakeIPTables() *fakeIPTables {
|
||||
return &fakeIPTables{
|
||||
tables: make(map[string]*fakeTable, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (f *fakeIPTables) GetVersion() (string, error) {
|
||||
return "1.4.21", nil
|
||||
}
|
||||
|
||||
func (f *fakeIPTables) getTable(tableName utiliptables.Table) (*fakeTable, error) {
|
||||
table, ok := f.tables[string(tableName)]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Table %s does not exist", tableName)
|
||||
}
|
||||
return table, nil
|
||||
}
|
||||
|
||||
func (f *fakeIPTables) getChain(tableName utiliptables.Table, chainName utiliptables.Chain) (*fakeTable, *fakeChain, error) {
|
||||
table, err := f.getTable(tableName)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
chain, ok := table.chains[string(chainName)]
|
||||
if !ok {
|
||||
return table, nil, fmt.Errorf("Chain %s/%s does not exist", tableName, chainName)
|
||||
}
|
||||
|
||||
return table, chain, nil
|
||||
}
|
||||
|
||||
func (f *fakeIPTables) ensureChain(tableName utiliptables.Table, chainName utiliptables.Chain) (bool, *fakeChain) {
|
||||
table, chain, err := f.getChain(tableName, chainName)
|
||||
if err != nil {
|
||||
// either table or table+chain don't exist yet
|
||||
if table == nil {
|
||||
table = &fakeTable{
|
||||
name: tableName,
|
||||
chains: make(map[string]*fakeChain),
|
||||
}
|
||||
f.tables[string(tableName)] = table
|
||||
}
|
||||
chain := &fakeChain{
|
||||
name: chainName,
|
||||
rules: make([]string, 0),
|
||||
}
|
||||
table.chains[string(chainName)] = chain
|
||||
return false, chain
|
||||
}
|
||||
return true, chain
|
||||
}
|
||||
|
||||
func (f *fakeIPTables) EnsureChain(tableName utiliptables.Table, chainName utiliptables.Chain) (bool, error) {
|
||||
existed, _ := f.ensureChain(tableName, chainName)
|
||||
return existed, nil
|
||||
}
|
||||
|
||||
func (f *fakeIPTables) FlushChain(tableName utiliptables.Table, chainName utiliptables.Chain) error {
|
||||
_, chain, err := f.getChain(tableName, chainName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chain.rules = make([]string, 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeIPTables) DeleteChain(tableName utiliptables.Table, chainName utiliptables.Chain) error {
|
||||
table, _, err := f.getChain(tableName, chainName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
delete(table.chains, string(chainName))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Returns index of rule in array; < 0 if rule is not found
|
||||
func findRule(chain *fakeChain, rule string) int {
|
||||
for i, candidate := range chain.rules {
|
||||
if rule == candidate {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (f *fakeIPTables) ensureRule(position utiliptables.RulePosition, tableName utiliptables.Table, chainName utiliptables.Chain, rule string) (bool, error) {
|
||||
_, chain, err := f.getChain(tableName, chainName)
|
||||
if err != nil {
|
||||
_, chain = f.ensureChain(tableName, chainName)
|
||||
}
|
||||
|
||||
rule, err = normalizeRule(rule)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
ruleIdx := findRule(chain, rule)
|
||||
if ruleIdx >= 0 {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if position == utiliptables.Prepend {
|
||||
chain.rules = append([]string{rule}, chain.rules...)
|
||||
} else if position == utiliptables.Append {
|
||||
chain.rules = append(chain.rules, rule)
|
||||
} else {
|
||||
return false, fmt.Errorf("Unknown position argument %q", position)
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func normalizeRule(rule string) (string, error) {
|
||||
normalized := ""
|
||||
remaining := strings.TrimSpace(rule)
|
||||
for {
|
||||
var end int
|
||||
|
||||
if strings.HasPrefix(remaining, "--to-destination=") {
|
||||
remaining = strings.Replace(remaining, "=", " ", 1)
|
||||
}
|
||||
|
||||
if remaining[0] == '"' {
|
||||
end = strings.Index(remaining[1:], "\"")
|
||||
if end < 0 {
|
||||
return "", fmt.Errorf("Invalid rule syntax: mismatched quotes")
|
||||
}
|
||||
end += 2
|
||||
} else {
|
||||
end = strings.Index(remaining, " ")
|
||||
if end < 0 {
|
||||
end = len(remaining)
|
||||
}
|
||||
}
|
||||
arg := remaining[:end]
|
||||
|
||||
// Normalize un-prefixed IP addresses like iptables does
|
||||
if net.ParseIP(arg) != nil {
|
||||
arg = arg + "/32"
|
||||
}
|
||||
|
||||
if len(normalized) > 0 {
|
||||
normalized += " "
|
||||
}
|
||||
normalized += strings.TrimSpace(arg)
|
||||
if len(remaining) == end {
|
||||
break
|
||||
}
|
||||
remaining = remaining[end+1:]
|
||||
}
|
||||
return normalized, nil
|
||||
}
|
||||
|
||||
func (f *fakeIPTables) EnsureRule(position utiliptables.RulePosition, tableName utiliptables.Table, chainName utiliptables.Chain, args ...string) (bool, error) {
|
||||
ruleArgs := make([]string, 0)
|
||||
for _, arg := range args {
|
||||
// quote args with internal spaces (like comments)
|
||||
if strings.Index(arg, " ") >= 0 {
|
||||
arg = fmt.Sprintf("\"%s\"", arg)
|
||||
}
|
||||
ruleArgs = append(ruleArgs, arg)
|
||||
}
|
||||
return f.ensureRule(position, tableName, chainName, strings.Join(ruleArgs, " "))
|
||||
}
|
||||
|
||||
func (f *fakeIPTables) DeleteRule(tableName utiliptables.Table, chainName utiliptables.Chain, args ...string) error {
|
||||
_, chain, err := f.getChain(tableName, chainName)
|
||||
if err == nil {
|
||||
rule := strings.Join(args, " ")
|
||||
ruleIdx := findRule(chain, rule)
|
||||
if ruleIdx < 0 {
|
||||
return nil
|
||||
}
|
||||
chain.rules = append(chain.rules[:ruleIdx], chain.rules[ruleIdx+1:]...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeIPTables) IsIpv6() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func saveChain(chain *fakeChain, data *bytes.Buffer) {
|
||||
for _, rule := range chain.rules {
|
||||
data.WriteString(fmt.Sprintf("-A %s %s\n", chain.name, rule))
|
||||
}
|
||||
}
|
||||
|
||||
func (f *fakeIPTables) Save(tableName utiliptables.Table) ([]byte, error) {
|
||||
table, err := f.getTable(tableName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data := bytes.NewBuffer(nil)
|
||||
data.WriteString(fmt.Sprintf("*%s\n", table.name))
|
||||
|
||||
rules := bytes.NewBuffer(nil)
|
||||
for _, chain := range table.chains {
|
||||
data.WriteString(fmt.Sprintf(":%s - [0:0]\n", string(chain.name)))
|
||||
saveChain(chain, rules)
|
||||
}
|
||||
data.Write(rules.Bytes())
|
||||
data.WriteString("COMMIT\n")
|
||||
return data.Bytes(), nil
|
||||
}
|
||||
|
||||
func (f *fakeIPTables) SaveAll() ([]byte, error) {
|
||||
data := bytes.NewBuffer(nil)
|
||||
for _, table := range f.tables {
|
||||
tableData, err := f.Save(table.name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err = data.Write(tableData); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return data.Bytes(), nil
|
||||
}
|
||||
|
||||
func (f *fakeIPTables) restore(restoreTableName utiliptables.Table, data []byte, flush utiliptables.FlushFlag) error {
|
||||
buf := bytes.NewBuffer(data)
|
||||
var tableName utiliptables.Table
|
||||
for {
|
||||
line, err := buf.ReadString('\n')
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if line[0] == '#' {
|
||||
continue
|
||||
}
|
||||
|
||||
line = strings.TrimSuffix(line, "\n")
|
||||
if strings.HasPrefix(line, "*") {
|
||||
tableName = utiliptables.Table(line[1:])
|
||||
}
|
||||
if tableName != "" {
|
||||
if restoreTableName != "" && restoreTableName != tableName {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(line, ":") {
|
||||
chainName := utiliptables.Chain(strings.Split(line[1:], " ")[0])
|
||||
if flush == utiliptables.FlushTables {
|
||||
table, chain, _ := f.getChain(tableName, chainName)
|
||||
if chain != nil {
|
||||
delete(table.chains, string(chainName))
|
||||
}
|
||||
}
|
||||
_, _ = f.ensureChain(tableName, chainName)
|
||||
} else if strings.HasPrefix(line, "-A") {
|
||||
parts := strings.Split(line, " ")
|
||||
if len(parts) < 3 {
|
||||
return fmt.Errorf("Invalid iptables rule '%s'", line)
|
||||
}
|
||||
chainName := utiliptables.Chain(parts[1])
|
||||
rule := strings.TrimPrefix(line, fmt.Sprintf("-A %s ", chainName))
|
||||
_, err := f.ensureRule(utiliptables.Append, tableName, chainName, rule)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if strings.HasPrefix(line, "-X") {
|
||||
parts := strings.Split(line, " ")
|
||||
if len(parts) < 3 {
|
||||
return fmt.Errorf("Invalid iptables rule '%s'", line)
|
||||
}
|
||||
if err := f.DeleteChain(tableName, utiliptables.Chain(parts[1])); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if line == "COMMIT" {
|
||||
if restoreTableName == tableName {
|
||||
return nil
|
||||
}
|
||||
tableName = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeIPTables) Restore(tableName utiliptables.Table, data []byte, flush utiliptables.FlushFlag, counters utiliptables.RestoreCountersFlag) error {
|
||||
return f.restore(tableName, data, flush)
|
||||
}
|
||||
|
||||
func (f *fakeIPTables) RestoreAll(data []byte, flush utiliptables.FlushFlag, counters utiliptables.RestoreCountersFlag) error {
|
||||
return f.restore("", data, flush)
|
||||
}
|
||||
|
||||
func (f *fakeIPTables) AddReloadFunc(reloadFunc func()) {
|
||||
}
|
||||
|
||||
func (f *fakeIPTables) Destroy() {
|
||||
}
|
||||
386
vendor/k8s.io/kubernetes/pkg/kubelet/network/hostport/hostport.go
generated
vendored
Normal file
386
vendor/k8s.io/kubernetes/pkg/kubelet/network/hostport/hostport.go
generated
vendored
Normal file
|
|
@ -0,0 +1,386 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package hostport
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/base32"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
iptablesproxy "k8s.io/kubernetes/pkg/proxy/iptables"
|
||||
utildbus "k8s.io/kubernetes/pkg/util/dbus"
|
||||
utilexec "k8s.io/kubernetes/pkg/util/exec"
|
||||
utiliptables "k8s.io/kubernetes/pkg/util/iptables"
|
||||
)
|
||||
|
||||
const (
|
||||
// the hostport chain
|
||||
kubeHostportsChain utiliptables.Chain = "KUBE-HOSTPORTS"
|
||||
// prefix for hostport chains
|
||||
kubeHostportChainPrefix string = "KUBE-HP-"
|
||||
)
|
||||
|
||||
type HostportHandler interface {
|
||||
OpenPodHostportsAndSync(newPod *ActivePod, natInterfaceName string, activePods []*ActivePod) error
|
||||
SyncHostports(natInterfaceName string, activePods []*ActivePod) error
|
||||
}
|
||||
|
||||
type ActivePod struct {
|
||||
Pod *v1.Pod
|
||||
IP net.IP
|
||||
}
|
||||
|
||||
type hostportOpener func(*hostport) (closeable, error)
|
||||
|
||||
type handler struct {
|
||||
hostPortMap map[hostport]closeable
|
||||
iptables utiliptables.Interface
|
||||
portOpener hostportOpener
|
||||
}
|
||||
|
||||
func NewHostportHandler() HostportHandler {
|
||||
iptInterface := utiliptables.New(utilexec.New(), utildbus.New(), utiliptables.ProtocolIpv4)
|
||||
return &handler{
|
||||
hostPortMap: make(map[hostport]closeable),
|
||||
iptables: iptInterface,
|
||||
portOpener: openLocalPort,
|
||||
}
|
||||
}
|
||||
|
||||
type closeable interface {
|
||||
Close() error
|
||||
}
|
||||
|
||||
type hostport struct {
|
||||
port int32
|
||||
protocol string
|
||||
}
|
||||
|
||||
type targetPod struct {
|
||||
podFullName string
|
||||
podIP string
|
||||
}
|
||||
|
||||
func (hp *hostport) String() string {
|
||||
return fmt.Sprintf("%s:%d", hp.protocol, hp.port)
|
||||
}
|
||||
|
||||
//openPodHostports opens all hostport for pod and returns the map of hostport and socket
|
||||
func (h *handler) openHostports(pod *v1.Pod) error {
|
||||
var retErr error
|
||||
ports := make(map[hostport]closeable)
|
||||
for _, container := range pod.Spec.Containers {
|
||||
for _, port := range container.Ports {
|
||||
if port.HostPort <= 0 {
|
||||
// Ignore
|
||||
continue
|
||||
}
|
||||
hp := hostport{
|
||||
port: port.HostPort,
|
||||
protocol: strings.ToLower(string(port.Protocol)),
|
||||
}
|
||||
socket, err := h.portOpener(&hp)
|
||||
if err != nil {
|
||||
retErr = fmt.Errorf("Cannot open hostport %d for pod %s: %v", port.HostPort, kubecontainer.GetPodFullName(pod), err)
|
||||
break
|
||||
}
|
||||
ports[hp] = socket
|
||||
}
|
||||
if retErr != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
// If encounter any error, close all hostports that just got opened.
|
||||
if retErr != nil {
|
||||
for hp, socket := range ports {
|
||||
if err := socket.Close(); err != nil {
|
||||
glog.Errorf("Cannot clean up hostport %d for pod %s: %v", hp.port, kubecontainer.GetPodFullName(pod), err)
|
||||
}
|
||||
}
|
||||
return retErr
|
||||
}
|
||||
|
||||
for hostPort, socket := range ports {
|
||||
h.hostPortMap[hostPort] = socket
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// gatherAllHostports returns all hostports that should be presented on node,
|
||||
// given the list of pods running on that node and ignoring host network
|
||||
// pods (which don't need hostport <-> container port mapping).
|
||||
func gatherAllHostports(activePods []*ActivePod) (map[v1.ContainerPort]targetPod, error) {
|
||||
podHostportMap := make(map[v1.ContainerPort]targetPod)
|
||||
for _, r := range activePods {
|
||||
if r.IP.To4() == nil {
|
||||
return nil, fmt.Errorf("Invalid or missing pod %s IP", kubecontainer.GetPodFullName(r.Pod))
|
||||
}
|
||||
|
||||
// should not handle hostports for hostnetwork pods
|
||||
if r.Pod.Spec.HostNetwork {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, container := range r.Pod.Spec.Containers {
|
||||
for _, port := range container.Ports {
|
||||
if port.HostPort != 0 {
|
||||
podHostportMap[port] = targetPod{podFullName: kubecontainer.GetPodFullName(r.Pod), podIP: r.IP.String()}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return podHostportMap, nil
|
||||
}
|
||||
|
||||
// Join all words with spaces, terminate with newline and write to buf.
|
||||
func writeLine(buf *bytes.Buffer, words ...string) {
|
||||
buf.WriteString(strings.Join(words, " ") + "\n")
|
||||
}
|
||||
|
||||
//hostportChainName takes containerPort for a pod and returns associated iptables chain.
|
||||
// This is computed by hashing (sha256)
|
||||
// then encoding to base32 and truncating with the prefix "KUBE-SVC-". We do
|
||||
// this because IPTables Chain Names must be <= 28 chars long, and the longer
|
||||
// they are the harder they are to read.
|
||||
func hostportChainName(cp v1.ContainerPort, podFullName string) utiliptables.Chain {
|
||||
hash := sha256.Sum256([]byte(string(cp.HostPort) + string(cp.Protocol) + podFullName))
|
||||
encoded := base32.StdEncoding.EncodeToString(hash[:])
|
||||
return utiliptables.Chain(kubeHostportChainPrefix + encoded[:16])
|
||||
}
|
||||
|
||||
// OpenPodHostportsAndSync opens hostports for a new pod, gathers all hostports on
|
||||
// node, sets up iptables rules enable them. And finally clean up stale hostports.
|
||||
// 'newPod' must also be present in 'activePods'.
|
||||
func (h *handler) OpenPodHostportsAndSync(newPod *ActivePod, natInterfaceName string, activePods []*ActivePod) error {
|
||||
// try to open pod host port if specified
|
||||
if err := h.openHostports(newPod.Pod); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Add the new pod to active pods if it's not present.
|
||||
var found bool
|
||||
for _, p := range activePods {
|
||||
if p.Pod.UID == newPod.Pod.UID {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
activePods = append(activePods, newPod)
|
||||
}
|
||||
|
||||
return h.SyncHostports(natInterfaceName, activePods)
|
||||
}
|
||||
|
||||
// SyncHostports gathers all hostports on node and setup iptables rules enable them. And finally clean up stale hostports
|
||||
func (h *handler) SyncHostports(natInterfaceName string, activePods []*ActivePod) error {
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
glog.V(4).Infof("syncHostportsRules took %v", time.Since(start))
|
||||
}()
|
||||
|
||||
containerPortMap, err := gatherAllHostports(activePods)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
glog.V(4).Info("Ensuring kubelet hostport chains")
|
||||
// Ensure kubeHostportChain
|
||||
if _, err := h.iptables.EnsureChain(utiliptables.TableNAT, kubeHostportsChain); err != nil {
|
||||
return fmt.Errorf("Failed to ensure that %s chain %s exists: %v", utiliptables.TableNAT, kubeHostportsChain, err)
|
||||
}
|
||||
tableChainsNeedJumpServices := []struct {
|
||||
table utiliptables.Table
|
||||
chain utiliptables.Chain
|
||||
}{
|
||||
{utiliptables.TableNAT, utiliptables.ChainOutput},
|
||||
{utiliptables.TableNAT, utiliptables.ChainPrerouting},
|
||||
}
|
||||
args := []string{"-m", "comment", "--comment", "kube hostport portals",
|
||||
"-m", "addrtype", "--dst-type", "LOCAL",
|
||||
"-j", string(kubeHostportsChain)}
|
||||
for _, tc := range tableChainsNeedJumpServices {
|
||||
if _, err := h.iptables.EnsureRule(utiliptables.Prepend, tc.table, tc.chain, args...); err != nil {
|
||||
return fmt.Errorf("Failed to ensure that %s chain %s jumps to %s: %v", tc.table, tc.chain, kubeHostportsChain, err)
|
||||
}
|
||||
}
|
||||
// Need to SNAT traffic from localhost
|
||||
args = []string{"-m", "comment", "--comment", "SNAT for localhost access to hostports", "-o", natInterfaceName, "-s", "127.0.0.0/8", "-j", "MASQUERADE"}
|
||||
if _, err := h.iptables.EnsureRule(utiliptables.Append, utiliptables.TableNAT, utiliptables.ChainPostrouting, args...); err != nil {
|
||||
return fmt.Errorf("Failed to ensure that %s chain %s jumps to MASQUERADE: %v", utiliptables.TableNAT, utiliptables.ChainPostrouting, err)
|
||||
}
|
||||
|
||||
// Get iptables-save output so we can check for existing chains and rules.
|
||||
// This will be a map of chain name to chain with rules as stored in iptables-save/iptables-restore
|
||||
existingNATChains := make(map[utiliptables.Chain]string)
|
||||
iptablesSaveRaw, err := h.iptables.Save(utiliptables.TableNAT)
|
||||
if err != nil { // if we failed to get any rules
|
||||
glog.Errorf("Failed to execute iptables-save, syncing all rules: %v", err)
|
||||
} else { // otherwise parse the output
|
||||
existingNATChains = utiliptables.GetChainLines(utiliptables.TableNAT, iptablesSaveRaw)
|
||||
}
|
||||
|
||||
natChains := bytes.NewBuffer(nil)
|
||||
natRules := bytes.NewBuffer(nil)
|
||||
writeLine(natChains, "*nat")
|
||||
// Make sure we keep stats for the top-level chains, if they existed
|
||||
// (which most should have because we created them above).
|
||||
if chain, ok := existingNATChains[kubeHostportsChain]; ok {
|
||||
writeLine(natChains, chain)
|
||||
} else {
|
||||
writeLine(natChains, utiliptables.MakeChainLine(kubeHostportsChain))
|
||||
}
|
||||
|
||||
// Accumulate NAT chains to keep.
|
||||
activeNATChains := map[utiliptables.Chain]bool{} // use a map as a set
|
||||
|
||||
for containerPort, target := range containerPortMap {
|
||||
protocol := strings.ToLower(string(containerPort.Protocol))
|
||||
hostportChain := hostportChainName(containerPort, target.podFullName)
|
||||
if chain, ok := existingNATChains[hostportChain]; ok {
|
||||
writeLine(natChains, chain)
|
||||
} else {
|
||||
writeLine(natChains, utiliptables.MakeChainLine(hostportChain))
|
||||
}
|
||||
|
||||
activeNATChains[hostportChain] = true
|
||||
|
||||
// Redirect to hostport chain
|
||||
args := []string{
|
||||
"-A", string(kubeHostportsChain),
|
||||
"-m", "comment", "--comment", fmt.Sprintf(`"%s hostport %d"`, target.podFullName, containerPort.HostPort),
|
||||
"-m", protocol, "-p", protocol,
|
||||
"--dport", fmt.Sprintf("%d", containerPort.HostPort),
|
||||
"-j", string(hostportChain),
|
||||
}
|
||||
writeLine(natRules, args...)
|
||||
|
||||
// Assuming kubelet is syncing iptables KUBE-MARK-MASQ chain
|
||||
// If the request comes from the pod that is serving the hostport, then SNAT
|
||||
args = []string{
|
||||
"-A", string(hostportChain),
|
||||
"-m", "comment", "--comment", fmt.Sprintf(`"%s hostport %d"`, target.podFullName, containerPort.HostPort),
|
||||
"-s", target.podIP, "-j", string(iptablesproxy.KubeMarkMasqChain),
|
||||
}
|
||||
writeLine(natRules, args...)
|
||||
|
||||
// Create hostport chain to DNAT traffic to final destination
|
||||
// IPTables will maintained the stats for this chain
|
||||
args = []string{
|
||||
"-A", string(hostportChain),
|
||||
"-m", "comment", "--comment", fmt.Sprintf(`"%s hostport %d"`, target.podFullName, containerPort.HostPort),
|
||||
"-m", protocol, "-p", protocol,
|
||||
"-j", "DNAT", fmt.Sprintf("--to-destination=%s:%d", target.podIP, containerPort.ContainerPort),
|
||||
}
|
||||
writeLine(natRules, args...)
|
||||
}
|
||||
|
||||
// Delete chains no longer in use.
|
||||
for chain := range existingNATChains {
|
||||
if !activeNATChains[chain] {
|
||||
chainString := string(chain)
|
||||
if !strings.HasPrefix(chainString, kubeHostportChainPrefix) {
|
||||
// Ignore chains that aren't ours.
|
||||
continue
|
||||
}
|
||||
// We must (as per iptables) write a chain-line for it, which has
|
||||
// the nice effect of flushing the chain. Then we can remove the
|
||||
// chain.
|
||||
writeLine(natChains, existingNATChains[chain])
|
||||
writeLine(natRules, "-X", chainString)
|
||||
}
|
||||
}
|
||||
writeLine(natRules, "COMMIT")
|
||||
|
||||
natLines := append(natChains.Bytes(), natRules.Bytes()...)
|
||||
glog.V(3).Infof("Restoring iptables rules: %s", natLines)
|
||||
err = h.iptables.RestoreAll(natLines, utiliptables.NoFlushTables, utiliptables.RestoreCounters)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to execute iptables-restore: %v", err)
|
||||
}
|
||||
|
||||
h.cleanupHostportMap(containerPortMap)
|
||||
return nil
|
||||
}
|
||||
|
||||
func openLocalPort(hp *hostport) (closeable, error) {
|
||||
// For ports on node IPs, open the actual port and hold it, even though we
|
||||
// use iptables to redirect traffic.
|
||||
// This ensures a) that it's safe to use that port and b) that (a) stays
|
||||
// true. The risk is that some process on the node (e.g. sshd or kubelet)
|
||||
// is using a port and we give that same port out to a Service. That would
|
||||
// be bad because iptables would silently claim the traffic but the process
|
||||
// would never know.
|
||||
// NOTE: We should not need to have a real listen()ing socket - bind()
|
||||
// should be enough, but I can't figure out a way to e2e test without
|
||||
// it. Tools like 'ss' and 'netstat' do not show sockets that are
|
||||
// bind()ed but not listen()ed, and at least the default debian netcat
|
||||
// has no way to avoid about 10 seconds of retries.
|
||||
var socket closeable
|
||||
switch hp.protocol {
|
||||
case "tcp":
|
||||
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", hp.port))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
socket = listener
|
||||
case "udp":
|
||||
addr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", hp.port))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn, err := net.ListenUDP("udp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
socket = conn
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown protocol %q", hp.protocol)
|
||||
}
|
||||
glog.V(3).Infof("Opened local port %s", hp.String())
|
||||
return socket, nil
|
||||
}
|
||||
|
||||
// cleanupHostportMap closes obsolete hostports
|
||||
func (h *handler) cleanupHostportMap(containerPortMap map[v1.ContainerPort]targetPod) {
|
||||
// compute hostports that are supposed to be open
|
||||
currentHostports := make(map[hostport]bool)
|
||||
for containerPort := range containerPortMap {
|
||||
hp := hostport{
|
||||
port: containerPort.HostPort,
|
||||
protocol: strings.ToLower(string(containerPort.Protocol)),
|
||||
}
|
||||
currentHostports[hp] = true
|
||||
}
|
||||
|
||||
// close and delete obsolete hostports
|
||||
for hp, socket := range h.hostPortMap {
|
||||
if _, ok := currentHostports[hp]; !ok {
|
||||
socket.Close()
|
||||
glog.V(3).Infof("Closed local port %s", hp.String())
|
||||
delete(h.hostPortMap, hp)
|
||||
}
|
||||
}
|
||||
}
|
||||
254
vendor/k8s.io/kubernetes/pkg/kubelet/network/hostport/hostport_test.go
generated
vendored
Normal file
254
vendor/k8s.io/kubernetes/pkg/kubelet/network/hostport/hostport_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package hostport
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
utiliptables "k8s.io/kubernetes/pkg/util/iptables"
|
||||
)
|
||||
|
||||
type fakeSocket struct {
|
||||
port int32
|
||||
protocol string
|
||||
closed bool
|
||||
}
|
||||
|
||||
func (f *fakeSocket) Close() error {
|
||||
if f.closed {
|
||||
return fmt.Errorf("Socket %q.%s already closed!", f.port, f.protocol)
|
||||
}
|
||||
f.closed = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func openFakeSocket(hp *hostport) (closeable, error) {
|
||||
return &fakeSocket{hp.port, hp.protocol, false}, nil
|
||||
}
|
||||
|
||||
type ruleMatch struct {
|
||||
hostport int
|
||||
chain string
|
||||
match string
|
||||
}
|
||||
|
||||
func TestOpenPodHostports(t *testing.T) {
|
||||
fakeIPTables := NewFakeIPTables()
|
||||
|
||||
h := &handler{
|
||||
hostPortMap: make(map[hostport]closeable),
|
||||
iptables: fakeIPTables,
|
||||
portOpener: openFakeSocket,
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
pod *v1.Pod
|
||||
ip string
|
||||
matches []*ruleMatch
|
||||
}{
|
||||
// New pod that we are going to add
|
||||
{
|
||||
&v1.Pod{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "test-pod",
|
||||
Namespace: v1.NamespaceDefault,
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{{
|
||||
Ports: []v1.ContainerPort{{
|
||||
HostPort: 4567,
|
||||
ContainerPort: 80,
|
||||
Protocol: v1.ProtocolTCP,
|
||||
}, {
|
||||
HostPort: 5678,
|
||||
ContainerPort: 81,
|
||||
Protocol: v1.ProtocolUDP,
|
||||
}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
"10.1.1.2",
|
||||
[]*ruleMatch{
|
||||
{
|
||||
-1,
|
||||
"KUBE-HOSTPORTS",
|
||||
"-m comment --comment \"test-pod_default hostport 4567\" -m tcp -p tcp --dport 4567",
|
||||
},
|
||||
{
|
||||
4567,
|
||||
"",
|
||||
"-m comment --comment \"test-pod_default hostport 4567\" -s 10.1.1.2/32 -j KUBE-MARK-MASQ",
|
||||
},
|
||||
{
|
||||
4567,
|
||||
"",
|
||||
"-m comment --comment \"test-pod_default hostport 4567\" -m tcp -p tcp -j DNAT --to-destination 10.1.1.2:80",
|
||||
},
|
||||
{
|
||||
-1,
|
||||
"KUBE-HOSTPORTS",
|
||||
"-m comment --comment \"test-pod_default hostport 5678\" -m udp -p udp --dport 5678",
|
||||
},
|
||||
{
|
||||
5678,
|
||||
"",
|
||||
"-m comment --comment \"test-pod_default hostport 5678\" -s 10.1.1.2/32 -j KUBE-MARK-MASQ",
|
||||
},
|
||||
{
|
||||
5678,
|
||||
"",
|
||||
"-m comment --comment \"test-pod_default hostport 5678\" -m udp -p udp -j DNAT --to-destination 10.1.1.2:81",
|
||||
},
|
||||
},
|
||||
},
|
||||
// Already running pod
|
||||
{
|
||||
&v1.Pod{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "another-test-pod",
|
||||
Namespace: v1.NamespaceDefault,
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{{
|
||||
Ports: []v1.ContainerPort{{
|
||||
HostPort: 123,
|
||||
ContainerPort: 654,
|
||||
Protocol: v1.ProtocolTCP,
|
||||
}},
|
||||
}},
|
||||
},
|
||||
},
|
||||
"10.1.1.5",
|
||||
[]*ruleMatch{
|
||||
{
|
||||
-1,
|
||||
"KUBE-HOSTPORTS",
|
||||
"-m comment --comment \"another-test-pod_default hostport 123\" -m tcp -p tcp --dport 123",
|
||||
},
|
||||
{
|
||||
123,
|
||||
"",
|
||||
"-m comment --comment \"another-test-pod_default hostport 123\" -s 10.1.1.5/32 -j KUBE-MARK-MASQ",
|
||||
},
|
||||
{
|
||||
123,
|
||||
"",
|
||||
"-m comment --comment \"another-test-pod_default hostport 123\" -m tcp -p tcp -j DNAT --to-destination 10.1.1.5:654",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
activePods := make([]*ActivePod, 0)
|
||||
|
||||
// Fill in any match rules missing chain names
|
||||
for _, test := range tests {
|
||||
for _, match := range test.matches {
|
||||
if match.hostport >= 0 {
|
||||
found := false
|
||||
for _, c := range test.pod.Spec.Containers {
|
||||
for _, cp := range c.Ports {
|
||||
if int(cp.HostPort) == match.hostport {
|
||||
match.chain = string(hostportChainName(cp, kubecontainer.GetPodFullName(test.pod)))
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Fatalf("Failed to find ContainerPort for match %d/'%s'", match.hostport, match.match)
|
||||
}
|
||||
}
|
||||
}
|
||||
activePods = append(activePods, &ActivePod{
|
||||
Pod: test.pod,
|
||||
IP: net.ParseIP(test.ip),
|
||||
})
|
||||
}
|
||||
|
||||
// Already running pod's host port
|
||||
hp := hostport{
|
||||
tests[1].pod.Spec.Containers[0].Ports[0].HostPort,
|
||||
strings.ToLower(string(tests[1].pod.Spec.Containers[0].Ports[0].Protocol)),
|
||||
}
|
||||
h.hostPortMap[hp] = &fakeSocket{
|
||||
tests[1].pod.Spec.Containers[0].Ports[0].HostPort,
|
||||
strings.ToLower(string(tests[1].pod.Spec.Containers[0].Ports[0].Protocol)),
|
||||
false,
|
||||
}
|
||||
|
||||
err := h.OpenPodHostportsAndSync(&ActivePod{Pod: tests[0].pod, IP: net.ParseIP(tests[0].ip)}, "br0", activePods)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to OpenPodHostportsAndSync: %v", err)
|
||||
}
|
||||
|
||||
// Generic rules
|
||||
genericRules := []*ruleMatch{
|
||||
{-1, "POSTROUTING", "-m comment --comment \"SNAT for localhost access to hostports\" -o br0 -s 127.0.0.0/8 -j MASQUERADE"},
|
||||
{-1, "PREROUTING", "-m comment --comment \"kube hostport portals\" -m addrtype --dst-type LOCAL -j KUBE-HOSTPORTS"},
|
||||
{-1, "OUTPUT", "-m comment --comment \"kube hostport portals\" -m addrtype --dst-type LOCAL -j KUBE-HOSTPORTS"},
|
||||
}
|
||||
|
||||
for _, rule := range genericRules {
|
||||
_, chain, err := fakeIPTables.getChain(utiliptables.TableNAT, utiliptables.Chain(rule.chain))
|
||||
if err != nil {
|
||||
t.Fatalf("Expected NAT chain %s did not exist", rule.chain)
|
||||
}
|
||||
if !matchRule(chain, rule.match) {
|
||||
t.Fatalf("Expected %s chain rule match '%s' not found", rule.chain, rule.match)
|
||||
}
|
||||
}
|
||||
|
||||
// Pod rules
|
||||
for _, test := range tests {
|
||||
for _, match := range test.matches {
|
||||
// Ensure chain exists
|
||||
_, chain, err := fakeIPTables.getChain(utiliptables.TableNAT, utiliptables.Chain(match.chain))
|
||||
if err != nil {
|
||||
t.Fatalf("Expected NAT chain %s did not exist", match.chain)
|
||||
}
|
||||
if !matchRule(chain, match.match) {
|
||||
t.Fatalf("Expected NAT chain %s rule containing '%s' not found", match.chain, match.match)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Socket
|
||||
hostPortMap := map[hostport]closeable{
|
||||
hostport{123, "tcp"}: &fakeSocket{123, "tcp", false},
|
||||
hostport{4567, "tcp"}: &fakeSocket{4567, "tcp", false},
|
||||
hostport{5678, "udp"}: &fakeSocket{5678, "udp", false},
|
||||
}
|
||||
if !reflect.DeepEqual(hostPortMap, h.hostPortMap) {
|
||||
t.Fatalf("Mismatch in expected hostPortMap. Expected '%v', got '%v'", hostPortMap, h.hostPortMap)
|
||||
}
|
||||
}
|
||||
|
||||
func matchRule(chain *fakeChain, match string) bool {
|
||||
for _, rule := range chain.rules {
|
||||
if strings.Contains(rule, match) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
21
vendor/k8s.io/kubernetes/pkg/kubelet/network/hostport/testing/BUILD
generated
vendored
Normal file
21
vendor/k8s.io/kubernetes/pkg/kubelet/network/hostport/testing/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["fake.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/kubelet/container:go_default_library",
|
||||
"//pkg/kubelet/network/hostport:go_default_library",
|
||||
],
|
||||
)
|
||||
44
vendor/k8s.io/kubernetes/pkg/kubelet/network/hostport/testing/fake.go
generated
vendored
Normal file
44
vendor/k8s.io/kubernetes/pkg/kubelet/network/hostport/testing/fake.go
generated
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package testing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
"k8s.io/kubernetes/pkg/kubelet/network/hostport"
|
||||
)
|
||||
|
||||
type fakeHandler struct{}
|
||||
|
||||
func NewFakeHostportHandler() hostport.HostportHandler {
|
||||
return &fakeHandler{}
|
||||
}
|
||||
|
||||
func (h *fakeHandler) OpenPodHostportsAndSync(newPod *hostport.ActivePod, natInterfaceName string, activePods []*hostport.ActivePod) error {
|
||||
return h.SyncHostports(natInterfaceName, activePods)
|
||||
}
|
||||
|
||||
func (h *fakeHandler) SyncHostports(natInterfaceName string, activePods []*hostport.ActivePod) error {
|
||||
for _, r := range activePods {
|
||||
if r.IP.To4() == nil {
|
||||
return fmt.Errorf("Invalid or missing pod %s IP", kubecontainer.GetPodFullName(r.Pod))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
59
vendor/k8s.io/kubernetes/pkg/kubelet/network/kubenet/BUILD
generated
vendored
Normal file
59
vendor/k8s.io/kubernetes/pkg/kubelet/network/kubenet/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["kubenet_linux.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/componentconfig:go_default_library",
|
||||
"//pkg/kubelet/container:go_default_library",
|
||||
"//pkg/kubelet/network:go_default_library",
|
||||
"//pkg/kubelet/network/hostport:go_default_library",
|
||||
"//pkg/util/bandwidth:go_default_library",
|
||||
"//pkg/util/dbus:go_default_library",
|
||||
"//pkg/util/ebtables:go_default_library",
|
||||
"//pkg/util/errors:go_default_library",
|
||||
"//pkg/util/exec:go_default_library",
|
||||
"//pkg/util/iptables:go_default_library",
|
||||
"//pkg/util/net:go_default_library",
|
||||
"//pkg/util/sets:go_default_library",
|
||||
"//pkg/util/sysctl:go_default_library",
|
||||
"//vendor:github.com/containernetworking/cni/libcni",
|
||||
"//vendor:github.com/containernetworking/cni/pkg/types",
|
||||
"//vendor:github.com/golang/glog",
|
||||
"//vendor:github.com/vishvananda/netlink",
|
||||
"//vendor:github.com/vishvananda/netlink/nl",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["kubenet_linux_test.go"],
|
||||
library = "go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/apis/componentconfig:go_default_library",
|
||||
"//pkg/kubelet/container:go_default_library",
|
||||
"//pkg/kubelet/network:go_default_library",
|
||||
"//pkg/kubelet/network/cni/testing:go_default_library",
|
||||
"//pkg/kubelet/network/hostport/testing:go_default_library",
|
||||
"//pkg/kubelet/network/testing:go_default_library",
|
||||
"//pkg/util/bandwidth:go_default_library",
|
||||
"//pkg/util/exec:go_default_library",
|
||||
"//pkg/util/iptables/testing:go_default_library",
|
||||
"//pkg/util/sysctl/testing:go_default_library",
|
||||
"//vendor:github.com/stretchr/testify/assert",
|
||||
"//vendor:github.com/stretchr/testify/mock",
|
||||
],
|
||||
)
|
||||
856
vendor/k8s.io/kubernetes/pkg/kubelet/network/kubenet/kubenet_linux.go
generated
vendored
Normal file
856
vendor/k8s.io/kubernetes/pkg/kubelet/network/kubenet/kubenet_linux.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
268
vendor/k8s.io/kubernetes/pkg/kubelet/network/kubenet/kubenet_linux_test.go
generated
vendored
Normal file
268
vendor/k8s.io/kubernetes/pkg/kubelet/network/kubenet/kubenet_linux_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
Copyright 2015 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kubenet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/componentconfig"
|
||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
"k8s.io/kubernetes/pkg/kubelet/network"
|
||||
"k8s.io/kubernetes/pkg/kubelet/network/cni/testing"
|
||||
hostporttest "k8s.io/kubernetes/pkg/kubelet/network/hostport/testing"
|
||||
nettest "k8s.io/kubernetes/pkg/kubelet/network/testing"
|
||||
"k8s.io/kubernetes/pkg/util/bandwidth"
|
||||
"k8s.io/kubernetes/pkg/util/exec"
|
||||
ipttest "k8s.io/kubernetes/pkg/util/iptables/testing"
|
||||
sysctltest "k8s.io/kubernetes/pkg/util/sysctl/testing"
|
||||
)
|
||||
|
||||
// test it fulfills the NetworkPlugin interface
|
||||
var _ network.NetworkPlugin = &kubenetNetworkPlugin{}
|
||||
|
||||
func newFakeKubenetPlugin(initMap map[kubecontainer.ContainerID]string, execer exec.Interface, host network.Host) *kubenetNetworkPlugin {
|
||||
return &kubenetNetworkPlugin{
|
||||
podIPs: initMap,
|
||||
execer: execer,
|
||||
mtu: 1460,
|
||||
host: host,
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetPodNetworkStatus(t *testing.T) {
|
||||
podIPMap := make(map[kubecontainer.ContainerID]string)
|
||||
podIPMap[kubecontainer.ContainerID{ID: "1"}] = "10.245.0.2"
|
||||
podIPMap[kubecontainer.ContainerID{ID: "2"}] = "10.245.0.3"
|
||||
|
||||
testCases := []struct {
|
||||
id string
|
||||
expectError bool
|
||||
expectIP string
|
||||
}{
|
||||
//in podCIDR map
|
||||
{
|
||||
"1",
|
||||
false,
|
||||
"10.245.0.2",
|
||||
},
|
||||
{
|
||||
"2",
|
||||
false,
|
||||
"10.245.0.3",
|
||||
},
|
||||
//not in podCIDR map
|
||||
{
|
||||
"3",
|
||||
true,
|
||||
"",
|
||||
},
|
||||
//TODO: add test cases for retrieving ip inside container network namespace
|
||||
}
|
||||
|
||||
fakeCmds := make([]exec.FakeCommandAction, 0)
|
||||
for _, t := range testCases {
|
||||
// the fake commands return the IP from the given index, or an error
|
||||
fCmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
func() ([]byte, error) {
|
||||
ip, ok := podIPMap[kubecontainer.ContainerID{ID: t.id}]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Pod IP %q not found", t.id)
|
||||
}
|
||||
return []byte(ip), nil
|
||||
},
|
||||
},
|
||||
}
|
||||
fakeCmds = append(fakeCmds, func(cmd string, args ...string) exec.Cmd {
|
||||
return exec.InitFakeCmd(&fCmd, cmd, args...)
|
||||
})
|
||||
}
|
||||
fexec := exec.FakeExec{
|
||||
CommandScript: fakeCmds,
|
||||
LookPathFunc: func(file string) (string, error) {
|
||||
return fmt.Sprintf("/fake-bin/%s", file), nil
|
||||
},
|
||||
}
|
||||
|
||||
fhost := nettest.NewFakeHost(nil)
|
||||
fakeKubenet := newFakeKubenetPlugin(podIPMap, &fexec, fhost)
|
||||
|
||||
for i, tc := range testCases {
|
||||
out, err := fakeKubenet.GetPodNetworkStatus("", "", kubecontainer.ContainerID{ID: tc.id})
|
||||
if tc.expectError {
|
||||
if err == nil {
|
||||
t.Errorf("Test case %d expects error but got none", i)
|
||||
}
|
||||
continue
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("Test case %d expects error but got error: %v", i, err)
|
||||
}
|
||||
}
|
||||
if tc.expectIP != out.IP.String() {
|
||||
t.Errorf("Test case %d expects ip %s but got %s", i, tc.expectIP, out.IP.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestTeardownBeforeSetUp tests that a `TearDown` call does call
|
||||
// `shaper.Reset`
|
||||
func TestTeardownCallsShaper(t *testing.T) {
|
||||
fexec := &exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{},
|
||||
LookPathFunc: func(file string) (string, error) {
|
||||
return fmt.Sprintf("/fake-bin/%s", file), nil
|
||||
},
|
||||
}
|
||||
fhost := nettest.NewFakeHost(nil)
|
||||
fshaper := &bandwidth.FakeShaper{}
|
||||
mockcni := &mock_cni.MockCNI{}
|
||||
kubenet := newFakeKubenetPlugin(map[kubecontainer.ContainerID]string{}, fexec, fhost)
|
||||
kubenet.cniConfig = mockcni
|
||||
kubenet.iptables = ipttest.NewFake()
|
||||
kubenet.bandwidthShaper = fshaper
|
||||
kubenet.hostportHandler = hostporttest.NewFakeHostportHandler()
|
||||
|
||||
mockcni.On("DelNetwork", mock.AnythingOfType("*libcni.NetworkConfig"), mock.AnythingOfType("*libcni.RuntimeConf")).Return(nil)
|
||||
|
||||
details := make(map[string]interface{})
|
||||
details[network.NET_PLUGIN_EVENT_POD_CIDR_CHANGE_DETAIL_CIDR] = "10.0.0.1/24"
|
||||
kubenet.Event(network.NET_PLUGIN_EVENT_POD_CIDR_CHANGE, details)
|
||||
|
||||
existingContainerID := kubecontainer.BuildContainerID("docker", "123")
|
||||
kubenet.podIPs[existingContainerID] = "10.0.0.1"
|
||||
|
||||
if err := kubenet.TearDownPod("namespace", "name", existingContainerID); err != nil {
|
||||
t.Fatalf("Unexpected error in TearDownPod: %v", err)
|
||||
}
|
||||
assert.Equal(t, []string{"10.0.0.1/32"}, fshaper.ResetCIDRs, "shaper.Reset should have been called")
|
||||
|
||||
mockcni.AssertExpectations(t)
|
||||
}
|
||||
|
||||
// TestInit tests that a `Init` call with an MTU sets the MTU
|
||||
func TestInit_MTU(t *testing.T) {
|
||||
var fakeCmds []exec.FakeCommandAction
|
||||
{
|
||||
// modprobe br-netfilter
|
||||
fCmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
func() ([]byte, error) {
|
||||
return make([]byte, 0), nil
|
||||
},
|
||||
},
|
||||
}
|
||||
fakeCmds = append(fakeCmds, func(cmd string, args ...string) exec.Cmd {
|
||||
return exec.InitFakeCmd(&fCmd, cmd, args...)
|
||||
})
|
||||
}
|
||||
|
||||
fexec := &exec.FakeExec{
|
||||
CommandScript: fakeCmds,
|
||||
LookPathFunc: func(file string) (string, error) {
|
||||
return fmt.Sprintf("/fake-bin/%s", file), nil
|
||||
},
|
||||
}
|
||||
|
||||
fhost := nettest.NewFakeHost(nil)
|
||||
kubenet := newFakeKubenetPlugin(map[kubecontainer.ContainerID]string{}, fexec, fhost)
|
||||
kubenet.iptables = ipttest.NewFake()
|
||||
|
||||
sysctl := sysctltest.NewFake()
|
||||
sysctl.Settings["net/bridge/bridge-nf-call-iptables"] = 0
|
||||
kubenet.sysctl = sysctl
|
||||
|
||||
if err := kubenet.Init(nettest.NewFakeHost(nil), componentconfig.HairpinNone, "10.0.0.0/8", 1234); err != nil {
|
||||
t.Fatalf("Unexpected error in Init: %v", err)
|
||||
}
|
||||
assert.Equal(t, 1234, kubenet.mtu, "kubenet.mtu should have been set")
|
||||
assert.Equal(t, 1, sysctl.Settings["net/bridge/bridge-nf-call-iptables"], "net/bridge/bridge-nf-call-iptables sysctl should have been set")
|
||||
}
|
||||
|
||||
func TestGenerateMacAddress(t *testing.T) {
|
||||
testCases := []struct {
|
||||
ip net.IP
|
||||
expectedMAC string
|
||||
}{
|
||||
{
|
||||
ip: net.ParseIP("10.0.0.2"),
|
||||
expectedMAC: privateMACPrefix + ":0a:00:00:02",
|
||||
},
|
||||
{
|
||||
ip: net.ParseIP("10.250.0.244"),
|
||||
expectedMAC: privateMACPrefix + ":0a:fa:00:f4",
|
||||
},
|
||||
{
|
||||
ip: net.ParseIP("172.17.0.2"),
|
||||
expectedMAC: privateMACPrefix + ":ac:11:00:02",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
mac, err := generateHardwareAddr(tc.ip)
|
||||
if err != nil {
|
||||
t.Errorf("Did not expect error: %v", err)
|
||||
}
|
||||
if mac.String() != tc.expectedMAC {
|
||||
t.Errorf("generated mac: %q, expecting: %q", mac.String(), tc.expectedMAC)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestInvocationWithoutRuntime invokes the plugin without a runtime.
|
||||
// This is how kubenet is invoked from the cri.
|
||||
func TestTearDownWithoutRuntime(t *testing.T) {
|
||||
fhost := nettest.NewFakeHost(nil)
|
||||
fhost.Legacy = false
|
||||
fhost.Runtime = nil
|
||||
mockcni := &mock_cni.MockCNI{}
|
||||
|
||||
fexec := &exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{},
|
||||
LookPathFunc: func(file string) (string, error) {
|
||||
return fmt.Sprintf("/fake-bin/%s", file), nil
|
||||
},
|
||||
}
|
||||
|
||||
kubenet := newFakeKubenetPlugin(map[kubecontainer.ContainerID]string{}, fexec, fhost)
|
||||
kubenet.cniConfig = mockcni
|
||||
kubenet.iptables = ipttest.NewFake()
|
||||
|
||||
details := make(map[string]interface{})
|
||||
details[network.NET_PLUGIN_EVENT_POD_CIDR_CHANGE_DETAIL_CIDR] = "10.0.0.1/24"
|
||||
kubenet.Event(network.NET_PLUGIN_EVENT_POD_CIDR_CHANGE, details)
|
||||
|
||||
existingContainerID := kubecontainer.BuildContainerID("docker", "123")
|
||||
kubenet.podIPs[existingContainerID] = "10.0.0.1"
|
||||
|
||||
mockcni.On("DelNetwork", mock.AnythingOfType("*libcni.NetworkConfig"), mock.AnythingOfType("*libcni.RuntimeConf")).Return(nil)
|
||||
|
||||
if err := kubenet.TearDownPod("namespace", "name", existingContainerID); err != nil {
|
||||
t.Fatalf("Unexpected error in TearDownPod: %v", err)
|
||||
}
|
||||
// Assert that the CNI DelNetwork made it through and we didn't crash
|
||||
// without a runtime.
|
||||
mockcni.AssertExpectations(t)
|
||||
}
|
||||
|
||||
//TODO: add unit test for each implementation of network plugin interface
|
||||
55
vendor/k8s.io/kubernetes/pkg/kubelet/network/kubenet/kubenet_unsupported.go
generated
vendored
Normal file
55
vendor/k8s.io/kubernetes/pkg/kubelet/network/kubenet/kubenet_unsupported.go
generated
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
// +build !linux
|
||||
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kubenet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/componentconfig"
|
||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
"k8s.io/kubernetes/pkg/kubelet/network"
|
||||
)
|
||||
|
||||
type kubenetNetworkPlugin struct {
|
||||
network.NoopNetworkPlugin
|
||||
}
|
||||
|
||||
func NewPlugin(networkPluginDir string) network.NetworkPlugin {
|
||||
return &kubenetNetworkPlugin{}
|
||||
}
|
||||
|
||||
func (plugin *kubenetNetworkPlugin) Init(host network.Host, hairpinMode componentconfig.HairpinMode, nonMasqueradeCIDR string, mtu int) error {
|
||||
return fmt.Errorf("Kubenet is not supported in this build")
|
||||
}
|
||||
|
||||
func (plugin *kubenetNetworkPlugin) Name() string {
|
||||
return "kubenet"
|
||||
}
|
||||
|
||||
func (plugin *kubenetNetworkPlugin) SetUpPod(namespace string, name string, id kubecontainer.ContainerID) error {
|
||||
return fmt.Errorf("Kubenet is not supported in this build")
|
||||
}
|
||||
|
||||
func (plugin *kubenetNetworkPlugin) TearDownPod(namespace string, name string, id kubecontainer.ContainerID) error {
|
||||
return fmt.Errorf("Kubenet is not supported in this build")
|
||||
}
|
||||
|
||||
func (plugin *kubenetNetworkPlugin) GetPodNetworkStatus(namespace string, name string, id kubecontainer.ContainerID) (*network.PodNetworkStatus, error) {
|
||||
return nil, fmt.Errorf("Kubenet is not supported in this build")
|
||||
}
|
||||
24
vendor/k8s.io/kubernetes/pkg/kubelet/network/mock_network/BUILD
generated
vendored
Normal file
24
vendor/k8s.io/kubernetes/pkg/kubelet/network/mock_network/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["network_plugins.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/apis/componentconfig:go_default_library",
|
||||
"//pkg/kubelet/container:go_default_library",
|
||||
"//pkg/kubelet/network:go_default_library",
|
||||
"//pkg/util/sets:go_default_library",
|
||||
"//vendor:github.com/golang/mock/gomock",
|
||||
],
|
||||
)
|
||||
133
vendor/k8s.io/kubernetes/pkg/kubelet/network/mock_network/network_plugins.go
generated
vendored
Normal file
133
vendor/k8s.io/kubernetes/pkg/kubelet/network/mock_network/network_plugins.go
generated
vendored
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Generated code, generated via: `mockgen k8s.io/kubernetes/pkg/kubelet/network NetworkPlugin > $GOPATH/src/k8s.io/kubernetes/pkg/kubelet/network/mock_network/network_plugins.go`
|
||||
// Edited by hand for boilerplate and gofmt.
|
||||
// TODO, this should be autogenerated/autoupdated by scripts.
|
||||
|
||||
package mock_network
|
||||
|
||||
import (
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
componentconfig "k8s.io/kubernetes/pkg/apis/componentconfig"
|
||||
container "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
network "k8s.io/kubernetes/pkg/kubelet/network"
|
||||
sets "k8s.io/kubernetes/pkg/util/sets"
|
||||
)
|
||||
|
||||
// Mock of NetworkPlugin interface
|
||||
type MockNetworkPlugin struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *_MockNetworkPluginRecorder
|
||||
}
|
||||
|
||||
// Recorder for MockNetworkPlugin (not exported)
|
||||
type _MockNetworkPluginRecorder struct {
|
||||
mock *MockNetworkPlugin
|
||||
}
|
||||
|
||||
func NewMockNetworkPlugin(ctrl *gomock.Controller) *MockNetworkPlugin {
|
||||
mock := &MockNetworkPlugin{ctrl: ctrl}
|
||||
mock.recorder = &_MockNetworkPluginRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
func (_m *MockNetworkPlugin) EXPECT() *_MockNetworkPluginRecorder {
|
||||
return _m.recorder
|
||||
}
|
||||
|
||||
func (_m *MockNetworkPlugin) Capabilities() sets.Int {
|
||||
ret := _m.ctrl.Call(_m, "Capabilities")
|
||||
ret0, _ := ret[0].(sets.Int)
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (_m *MockNetworkPlugin) Finish() {
|
||||
_m.ctrl.Finish()
|
||||
}
|
||||
|
||||
func (_mr *_MockNetworkPluginRecorder) Capabilities() *gomock.Call {
|
||||
return _mr.mock.ctrl.RecordCall(_mr.mock, "Capabilities")
|
||||
}
|
||||
|
||||
func (_m *MockNetworkPlugin) Event(_param0 string, _param1 map[string]interface{}) {
|
||||
_m.ctrl.Call(_m, "Event", _param0, _param1)
|
||||
}
|
||||
|
||||
func (_mr *_MockNetworkPluginRecorder) Event(arg0, arg1 interface{}) *gomock.Call {
|
||||
return _mr.mock.ctrl.RecordCall(_mr.mock, "Event", arg0, arg1)
|
||||
}
|
||||
|
||||
func (_m *MockNetworkPlugin) GetPodNetworkStatus(_param0 string, _param1 string, _param2 container.ContainerID) (*network.PodNetworkStatus, error) {
|
||||
ret := _m.ctrl.Call(_m, "GetPodNetworkStatus", _param0, _param1, _param2)
|
||||
ret0, _ := ret[0].(*network.PodNetworkStatus)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
func (_mr *_MockNetworkPluginRecorder) GetPodNetworkStatus(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
return _mr.mock.ctrl.RecordCall(_mr.mock, "GetPodNetworkStatus", arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
func (_m *MockNetworkPlugin) Init(_param0 network.Host, _param1 componentconfig.HairpinMode, nonMasqueradeCIDR string, mtu int) error {
|
||||
ret := _m.ctrl.Call(_m, "Init", _param0, _param1)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (_mr *_MockNetworkPluginRecorder) Init(arg0, arg1 interface{}) *gomock.Call {
|
||||
return _mr.mock.ctrl.RecordCall(_mr.mock, "Init", arg0, arg1)
|
||||
}
|
||||
|
||||
func (_m *MockNetworkPlugin) Name() string {
|
||||
ret := _m.ctrl.Call(_m, "Name")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (_mr *_MockNetworkPluginRecorder) Name() *gomock.Call {
|
||||
return _mr.mock.ctrl.RecordCall(_mr.mock, "Name")
|
||||
}
|
||||
|
||||
func (_m *MockNetworkPlugin) SetUpPod(_param0 string, _param1 string, _param2 container.ContainerID) error {
|
||||
ret := _m.ctrl.Call(_m, "SetUpPod", _param0, _param1, _param2)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (_mr *_MockNetworkPluginRecorder) SetUpPod(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
return _mr.mock.ctrl.RecordCall(_mr.mock, "SetUpPod", arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
func (_m *MockNetworkPlugin) Status() error {
|
||||
ret := _m.ctrl.Call(_m, "Status")
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (_mr *_MockNetworkPluginRecorder) Status() *gomock.Call {
|
||||
return _mr.mock.ctrl.RecordCall(_mr.mock, "Status")
|
||||
}
|
||||
|
||||
func (_m *MockNetworkPlugin) TearDownPod(_param0 string, _param1 string, _param2 container.ContainerID) error {
|
||||
ret := _m.ctrl.Call(_m, "TearDownPod", _param0, _param1, _param2)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (_mr *_MockNetworkPluginRecorder) TearDownPod(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
return _mr.mock.ctrl.RecordCall(_mr.mock, "TearDownPod", arg0, arg1, arg2)
|
||||
}
|
||||
24
vendor/k8s.io/kubernetes/pkg/kubelet/network/network.go
generated
vendored
Normal file
24
vendor/k8s.io/kubernetes/pkg/kubelet/network/network.go
generated
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package network
|
||||
|
||||
// TODO: Consider making this value configurable.
|
||||
const DefaultInterfaceName = "eth0"
|
||||
|
||||
// UseDefaultMTU is a marker value that indicates the plugin should determine its own MTU
|
||||
// It is the zero value, so a non-initialized value will mean "UseDefault"
|
||||
const UseDefaultMTU = 0
|
||||
279
vendor/k8s.io/kubernetes/pkg/kubelet/network/plugins.go
generated
vendored
Normal file
279
vendor/k8s.io/kubernetes/pkg/kubelet/network/plugins.go
generated
vendored
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/apis/componentconfig"
|
||||
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
|
||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
utilerrors "k8s.io/kubernetes/pkg/util/errors"
|
||||
utilexec "k8s.io/kubernetes/pkg/util/exec"
|
||||
utilsets "k8s.io/kubernetes/pkg/util/sets"
|
||||
utilsysctl "k8s.io/kubernetes/pkg/util/sysctl"
|
||||
"k8s.io/kubernetes/pkg/util/validation"
|
||||
)
|
||||
|
||||
const DefaultPluginName = "kubernetes.io/no-op"
|
||||
|
||||
// Called when the node's Pod CIDR is known when using the
|
||||
// controller manager's --allocate-node-cidrs=true option
|
||||
const NET_PLUGIN_EVENT_POD_CIDR_CHANGE = "pod-cidr-change"
|
||||
const NET_PLUGIN_EVENT_POD_CIDR_CHANGE_DETAIL_CIDR = "pod-cidr"
|
||||
|
||||
// Plugin capabilities
|
||||
const (
|
||||
// Indicates the plugin handles Kubernetes bandwidth shaping annotations internally
|
||||
NET_PLUGIN_CAPABILITY_SHAPING int = 1
|
||||
)
|
||||
|
||||
// Plugin is an interface to network plugins for the kubelet
|
||||
type NetworkPlugin interface {
|
||||
// Init initializes the plugin. This will be called exactly once
|
||||
// before any other methods are called.
|
||||
Init(host Host, hairpinMode componentconfig.HairpinMode, nonMasqueradeCIDR string, mtu int) error
|
||||
|
||||
// Called on various events like:
|
||||
// NET_PLUGIN_EVENT_POD_CIDR_CHANGE
|
||||
Event(name string, details map[string]interface{})
|
||||
|
||||
// Name returns the plugin's name. This will be used when searching
|
||||
// for a plugin by name, e.g.
|
||||
Name() string
|
||||
|
||||
// Returns a set of NET_PLUGIN_CAPABILITY_*
|
||||
Capabilities() utilsets.Int
|
||||
|
||||
// SetUpPod is the method called after the infra container of
|
||||
// the pod has been created but before the other containers of the
|
||||
// pod are launched.
|
||||
// TODO: rename podInfraContainerID to sandboxID
|
||||
SetUpPod(namespace string, name string, podInfraContainerID kubecontainer.ContainerID) error
|
||||
|
||||
// TearDownPod is the method called before a pod's infra container will be deleted
|
||||
// TODO: rename podInfraContainerID to sandboxID
|
||||
TearDownPod(namespace string, name string, podInfraContainerID kubecontainer.ContainerID) error
|
||||
|
||||
// Status is the method called to obtain the ipv4 or ipv6 addresses of the container
|
||||
// TODO: rename podInfraContainerID to sandboxID
|
||||
GetPodNetworkStatus(namespace string, name string, podInfraContainerID kubecontainer.ContainerID) (*PodNetworkStatus, error)
|
||||
|
||||
// NetworkStatus returns error if the network plugin is in error state
|
||||
Status() error
|
||||
}
|
||||
|
||||
// PodNetworkStatus stores the network status of a pod (currently just the primary IP address)
|
||||
// This struct represents version "v1beta1"
|
||||
type PodNetworkStatus struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
// IP is the primary ipv4/ipv6 address of the pod. Among other things it is the address that -
|
||||
// - kube expects to be reachable across the cluster
|
||||
// - service endpoints are constructed with
|
||||
// - will be reported in the PodStatus.PodIP field (will override the IP reported by docker)
|
||||
IP net.IP `json:"ip" description:"Primary IP address of the pod"`
|
||||
}
|
||||
|
||||
// LegacyHost implements the methods required by network plugins that
|
||||
// were directly invoked by the kubelet. Implementations of this interface
|
||||
// that do not wish to support these features can simply return false
|
||||
// to SupportsLegacyFeatures.
|
||||
type LegacyHost interface {
|
||||
// Get the pod structure by its name, namespace
|
||||
// Only used for hostport management and bw shaping
|
||||
GetPodByName(namespace, name string) (*v1.Pod, bool)
|
||||
|
||||
// GetKubeClient returns a client interface
|
||||
// Only used in testing
|
||||
GetKubeClient() clientset.Interface
|
||||
|
||||
// GetContainerRuntime returns the container runtime that implements the containers (e.g. docker/rkt)
|
||||
// Only used for hostport management
|
||||
GetRuntime() kubecontainer.Runtime
|
||||
|
||||
// SupportsLegacyFeaturs returns true if this host can support hostports
|
||||
// and bandwidth shaping. Both will either get added to CNI or dropped,
|
||||
// so differnt implementations can choose to ignore them.
|
||||
SupportsLegacyFeatures() bool
|
||||
}
|
||||
|
||||
// Host is an interface that plugins can use to access the kubelet.
|
||||
// TODO(#35457): get rid of this backchannel to the kubelet. The scope of
|
||||
// the back channel is restricted to host-ports/testing, and restricted
|
||||
// to kubenet. No other network plugin wrapper needs it. Other plugins
|
||||
// only require a way to access namespace information, which they can do
|
||||
// directly through the embedded NamespaceGetter.
|
||||
type Host interface {
|
||||
// NamespaceGetter is a getter for sandbox namespace information.
|
||||
// It's the only part of this interface that isn't currently deprecated.
|
||||
NamespaceGetter
|
||||
|
||||
// LegacyHost contains methods that trap back into the Kubelet. Dependence
|
||||
// *do not* add more dependencies in this interface. In a post-cri world,
|
||||
// network plugins will be invoked by the runtime shim, and should only
|
||||
// require NamespaceGetter.
|
||||
LegacyHost
|
||||
}
|
||||
|
||||
// NamespaceGetter is an interface to retrieve namespace information for a given
|
||||
// sandboxID. Typically implemented by runtime shims that are closely coupled to
|
||||
// CNI plugin wrappers like kubenet.
|
||||
type NamespaceGetter interface {
|
||||
// GetNetNS returns network namespace information for the given containerID.
|
||||
GetNetNS(containerID string) (string, error)
|
||||
}
|
||||
|
||||
// InitNetworkPlugin inits the plugin that matches networkPluginName. Plugins must have unique names.
|
||||
func InitNetworkPlugin(plugins []NetworkPlugin, networkPluginName string, host Host, hairpinMode componentconfig.HairpinMode, nonMasqueradeCIDR string, mtu int) (NetworkPlugin, error) {
|
||||
if networkPluginName == "" {
|
||||
// default to the no_op plugin
|
||||
plug := &NoopNetworkPlugin{}
|
||||
if err := plug.Init(host, hairpinMode, nonMasqueradeCIDR, mtu); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return plug, nil
|
||||
}
|
||||
|
||||
pluginMap := map[string]NetworkPlugin{}
|
||||
|
||||
allErrs := []error{}
|
||||
for _, plugin := range plugins {
|
||||
name := plugin.Name()
|
||||
if errs := validation.IsQualifiedName(name); len(errs) != 0 {
|
||||
allErrs = append(allErrs, fmt.Errorf("network plugin has invalid name: %q: %s", name, strings.Join(errs, ";")))
|
||||
continue
|
||||
}
|
||||
|
||||
if _, found := pluginMap[name]; found {
|
||||
allErrs = append(allErrs, fmt.Errorf("network plugin %q was registered more than once", name))
|
||||
continue
|
||||
}
|
||||
pluginMap[name] = plugin
|
||||
}
|
||||
|
||||
chosenPlugin := pluginMap[networkPluginName]
|
||||
if chosenPlugin != nil {
|
||||
err := chosenPlugin.Init(host, hairpinMode, nonMasqueradeCIDR, mtu)
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, fmt.Errorf("Network plugin %q failed init: %v", networkPluginName, err))
|
||||
} else {
|
||||
glog.V(1).Infof("Loaded network plugin %q", networkPluginName)
|
||||
}
|
||||
} else {
|
||||
allErrs = append(allErrs, fmt.Errorf("Network plugin %q not found.", networkPluginName))
|
||||
}
|
||||
|
||||
return chosenPlugin, utilerrors.NewAggregate(allErrs)
|
||||
}
|
||||
|
||||
func UnescapePluginName(in string) string {
|
||||
return strings.Replace(in, "~", "/", -1)
|
||||
}
|
||||
|
||||
type NoopNetworkPlugin struct {
|
||||
}
|
||||
|
||||
const sysctlBridgeCallIPTables = "net/bridge/bridge-nf-call-iptables"
|
||||
|
||||
func (plugin *NoopNetworkPlugin) Init(host Host, hairpinMode componentconfig.HairpinMode, nonMasqueradeCIDR string, mtu int) error {
|
||||
// Set bridge-nf-call-iptables=1 to maintain compatibility with older
|
||||
// kubernetes versions to ensure the iptables-based kube proxy functions
|
||||
// correctly. Other plugins are responsible for setting this correctly
|
||||
// depending on whether or not they connect containers to Linux bridges
|
||||
// or use some other mechanism (ie, SDN vswitch).
|
||||
|
||||
// Ensure the netfilter module is loaded on kernel >= 3.18; previously
|
||||
// it was built-in.
|
||||
utilexec.New().Command("modprobe", "br-netfilter").CombinedOutput()
|
||||
if err := utilsysctl.New().SetSysctl(sysctlBridgeCallIPTables, 1); err != nil {
|
||||
glog.Warningf("can't set sysctl %s: %v", sysctlBridgeCallIPTables, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (plugin *NoopNetworkPlugin) Event(name string, details map[string]interface{}) {
|
||||
}
|
||||
|
||||
func (plugin *NoopNetworkPlugin) Name() string {
|
||||
return DefaultPluginName
|
||||
}
|
||||
|
||||
func (plugin *NoopNetworkPlugin) Capabilities() utilsets.Int {
|
||||
return utilsets.NewInt()
|
||||
}
|
||||
|
||||
func (plugin *NoopNetworkPlugin) SetUpPod(namespace string, name string, id kubecontainer.ContainerID) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (plugin *NoopNetworkPlugin) TearDownPod(namespace string, name string, id kubecontainer.ContainerID) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (plugin *NoopNetworkPlugin) GetPodNetworkStatus(namespace string, name string, id kubecontainer.ContainerID) (*PodNetworkStatus, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (plugin *NoopNetworkPlugin) Status() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getOnePodIP(execer utilexec.Interface, nsenterPath, netnsPath, interfaceName, addrType string) (net.IP, error) {
|
||||
// Try to retrieve ip inside container network namespace
|
||||
output, err := execer.Command(nsenterPath, fmt.Sprintf("--net=%s", netnsPath), "-F", "--",
|
||||
"ip", "-o", addrType, "addr", "show", "dev", interfaceName, "scope", "global").CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unexpected command output %s with error: %v", output, err)
|
||||
}
|
||||
|
||||
lines := strings.Split(string(output), "\n")
|
||||
if len(lines) < 1 {
|
||||
return nil, fmt.Errorf("Unexpected command output %s", output)
|
||||
}
|
||||
fields := strings.Fields(lines[0])
|
||||
if len(fields) < 4 {
|
||||
return nil, fmt.Errorf("Unexpected address output %s ", lines[0])
|
||||
}
|
||||
ip, _, err := net.ParseCIDR(fields[3])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("CNI failed to parse ip from output %s due to %v", output, err)
|
||||
}
|
||||
|
||||
return ip, nil
|
||||
}
|
||||
|
||||
// GetPodIP gets the IP of the pod by inspecting the network info inside the pod's network namespace.
|
||||
func GetPodIP(execer utilexec.Interface, nsenterPath, netnsPath, interfaceName string) (net.IP, error) {
|
||||
ip, err := getOnePodIP(execer, nsenterPath, netnsPath, interfaceName, "-4")
|
||||
if err != nil {
|
||||
// Fall back to IPv6 address if no IPv4 address is present
|
||||
ip, err = getOnePodIP(execer, nsenterPath, netnsPath, interfaceName, "-6")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ip, nil
|
||||
}
|
||||
38
vendor/k8s.io/kubernetes/pkg/kubelet/network/plugins_test.go
generated
vendored
Normal file
38
vendor/k8s.io/kubernetes/pkg/kubelet/network/plugins_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package network
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/componentconfig"
|
||||
nettest "k8s.io/kubernetes/pkg/kubelet/network/testing"
|
||||
)
|
||||
|
||||
func TestSelectDefaultPlugin(t *testing.T) {
|
||||
all_plugins := []NetworkPlugin{}
|
||||
plug, err := InitNetworkPlugin(all_plugins, "", nettest.NewFakeHost(nil), componentconfig.HairpinNone, "10.0.0.0/8", UseDefaultMTU)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error in selecting default plugin: %v", err)
|
||||
}
|
||||
if plug == nil {
|
||||
t.Fatalf("Failed to select the default plugin.")
|
||||
}
|
||||
if plug.Name() != DefaultPluginName {
|
||||
t.Errorf("Failed to select the default plugin. Expected %s. Got %s", DefaultPluginName, plug.Name())
|
||||
}
|
||||
}
|
||||
23
vendor/k8s.io/kubernetes/pkg/kubelet/network/testing/BUILD
generated
vendored
Normal file
23
vendor/k8s.io/kubernetes/pkg/kubelet/network/testing/BUILD
generated
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_binary",
|
||||
"go_library",
|
||||
"go_test",
|
||||
"cgo_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["fake_host.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/client/clientset_generated/release_1_5:go_default_library",
|
||||
"//pkg/kubelet/container:go_default_library",
|
||||
"//pkg/kubelet/container/testing:go_default_library",
|
||||
],
|
||||
)
|
||||
63
vendor/k8s.io/kubernetes/pkg/kubelet/network/testing/fake_host.go
generated
vendored
Normal file
63
vendor/k8s.io/kubernetes/pkg/kubelet/network/testing/fake_host.go
generated
vendored
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package testing
|
||||
|
||||
// helper for testing plugins
|
||||
// a fake host is created here that can be used by plugins for testing
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/release_1_5"
|
||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
|
||||
)
|
||||
|
||||
type fakeNetworkHost struct {
|
||||
fakeNamespaceGetter
|
||||
kubeClient clientset.Interface
|
||||
Legacy bool
|
||||
Runtime *containertest.FakeRuntime
|
||||
}
|
||||
|
||||
func NewFakeHost(kubeClient clientset.Interface) *fakeNetworkHost {
|
||||
host := &fakeNetworkHost{kubeClient: kubeClient, Legacy: true, Runtime: &containertest.FakeRuntime{}}
|
||||
return host
|
||||
}
|
||||
|
||||
func (fnh *fakeNetworkHost) GetPodByName(name, namespace string) (*v1.Pod, bool) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (fnh *fakeNetworkHost) GetKubeClient() clientset.Interface {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (nh *fakeNetworkHost) GetRuntime() kubecontainer.Runtime {
|
||||
return nh.Runtime
|
||||
}
|
||||
|
||||
func (nh *fakeNetworkHost) SupportsLegacyFeatures() bool {
|
||||
return nh.Legacy
|
||||
}
|
||||
|
||||
type fakeNamespaceGetter struct {
|
||||
ns string
|
||||
}
|
||||
|
||||
func (nh *fakeNamespaceGetter) GetNetNS(containerID string) (string, error) {
|
||||
return nh.ns, nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue