Revert "Revert "[WIP] southbound networking hooks in kubelet""

pull/6/head
CJ Cullen 2015-03-19 16:14:13 -07:00
parent 1dd4600eb6
commit 7ddcecfd1c
11 changed files with 606 additions and 0 deletions

View File

@ -20,6 +20,9 @@ package app
import (
// Credential providers
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/credentialprovider/gcp"
// Network plugins
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/network"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/network/exec"
// Volume plugins
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/volume"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/volume/empty_dir"
@ -44,3 +47,13 @@ func ProbeVolumePlugins() []volume.Plugin {
return allPlugins
}
// ProbeNetworkPlugins collects all compiled-in plugins
func ProbeNetworkPlugins() []network.NetworkPlugin {
allPlugins := []network.NetworkPlugin{}
// for each existing plugin, add to the list
allPlugins = append(allPlugins, exec.ProbeNetworkPlugins()...)
return allPlugins
}

View File

@ -33,6 +33,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/cadvisor"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/config"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/network"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/volume"
"github.com/GoogleCloudPlatform/kubernetes/pkg/master/ports"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
@ -79,6 +80,7 @@ type KubeletServer struct {
StreamingConnectionIdleTimeout time.Duration
ImageGCHighThresholdPercent int
ImageGCLowThresholdPercent int
NetworkPluginName string
}
// NewKubeletServer will create a new KubeletServer with default values.
@ -104,6 +106,7 @@ func NewKubeletServer() *KubeletServer {
MasterServiceNamespace: api.NamespaceDefault,
ImageGCHighThresholdPercent: 90,
ImageGCLowThresholdPercent: 80,
NetworkPluginName: "",
}
}
@ -142,6 +145,7 @@ func (s *KubeletServer) AddFlags(fs *pflag.FlagSet) {
fs.DurationVar(&s.StreamingConnectionIdleTimeout, "streaming_connection_idle_timeout", 0, "Maximum time a streaming connection can be idle before the connection is automatically closed. Example: '5m'")
fs.IntVar(&s.ImageGCHighThresholdPercent, "image_gc_high_threshold", s.ImageGCHighThresholdPercent, "The percent of disk usage after which image garbage collection is always run. Default: 90%%")
fs.IntVar(&s.ImageGCLowThresholdPercent, "image_gc_low_threshold", s.ImageGCLowThresholdPercent, "The percent of disk usage before which image garbage collection is never run. Lowest disk usage to garbage collect to. Default: 80%%")
fs.StringVar(&s.NetworkPluginName, "network_plugin", s.NetworkPluginName, "<Warning: Alpha feature> The name of the network plugin to be invoked for various events in kubelet/pod lifecycle")
}
// Run runs the specified KubeletServer. This should never exit.
@ -200,6 +204,8 @@ func (s *KubeletServer) Run(_ []string) error {
KubeClient: client,
MasterServiceNamespace: s.MasterServiceNamespace,
VolumePlugins: ProbeVolumePlugins(),
NetworkPlugins: ProbeNetworkPlugins(),
NetworkPluginName: s.NetworkPluginName,
StreamingConnectionIdleTimeout: s.StreamingConnectionIdleTimeout,
ImageGCPolicy: imageGCPolicy,
}
@ -397,6 +403,8 @@ type KubeletConfig struct {
Runonce bool
MasterServiceNamespace string
VolumePlugins []volume.Plugin
NetworkPlugins []network.NetworkPlugin
NetworkPluginName string
StreamingConnectionIdleTimeout time.Duration
Recorder record.EventRecorder
TLSOptions *kubelet.TLSOptions
@ -437,6 +445,8 @@ func createAndInitKubelet(kc *KubeletConfig, pc *config.PodConfig) (*kubelet.Kub
net.IP(kc.ClusterDNS),
kc.MasterServiceNamespace,
kc.VolumePlugins,
kc.NetworkPlugins,
kc.NetworkPluginName,
kc.StreamingConnectionIdleTimeout,
kc.Recorder,
kc.CadvisorInterface,

View File

@ -42,6 +42,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/envvars"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/metrics"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/network"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/volume"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"github.com/GoogleCloudPlatform/kubernetes/pkg/probe"
@ -118,6 +119,8 @@ func NewMainKubelet(
clusterDNS net.IP,
masterServiceNamespace string,
volumePlugins []volume.Plugin,
networkPlugins []network.NetworkPlugin,
networkPluginName string,
streamingConnectionIdleTimeout time.Duration,
recorder record.EventRecorder,
cadvisorInterface cadvisor.Interface,
@ -220,6 +223,12 @@ func NewMainKubelet(
return nil, err
}
if plug, err := network.InitNetworkPlugin(networkPlugins, networkPluginName, &networkHost{klet}); err != nil {
return nil, err
} else {
klet.networkPlugin = plug
}
klet.podStatuses = make(map[string]api.PodStatus)
klet.mirrorManager = newBasicMirrorManager(klet.kubeClient)
@ -301,6 +310,9 @@ type Kubelet struct {
// Volume plugins.
volumePluginMgr volume.PluginMgr
// Network plugin
networkPlugin network.NetworkPlugin
// probe runner holder
prober probeHolder
// container readiness state holder
@ -1357,6 +1369,11 @@ func (kl *Kubelet) syncPod(pod *api.Pod, hasMirrorPod bool, containersInPod dock
}
glog.Infof("Creating pod infra container for %q", podFullName)
podInfraContainerID, err = kl.createPodInfraContainer(pod)
// Call the networking plugin
if err == nil {
err = kl.networkPlugin.SetUpPod(pod.Namespace, pod.Name, podInfraContainerID)
}
if err != nil {
glog.Errorf("Failed to create pod infra container: %v; Skipping pod %q", err, podFullName)
return err
@ -1548,6 +1565,14 @@ func (kl *Kubelet) SyncPods(allPods []api.Pod, podSyncTypes map[types.UID]metric
pc := podContainer{podFullName, uid, containerName}
_, ok := desiredContainers[pc]
if err != nil || !ok {
// call the networking plugin for teardown
if containerName == dockertools.PodInfraContainerName {
name, namespace, _ := ParsePodFullName(podFullName)
err := kl.networkPlugin.TearDownPod(namespace, name, dockertools.DockerID(dockerContainers[ix].ID))
if err != nil {
glog.Errorf("Network plugin pre-delete method returned an error: %v", err)
}
}
glog.V(1).Infof("Killing unwanted container %+v", pc)
err = kl.killContainer(dockerContainers[ix])
if err != nil {

View File

@ -39,6 +39,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/cadvisor"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/metrics"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/network"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/volume"
_ "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/volume/host_path"
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
@ -73,6 +74,7 @@ func newTestKubelet(t *testing.T) *TestKubelet {
kubelet.kubeClient = fakeKubeClient
kubelet.dockerPuller = &dockertools.FakeDockerPuller{}
kubelet.hostname = "testnode"
kubelet.networkPlugin, _ = network.InitNetworkPlugin([]network.NetworkPlugin{}, "", network.NewFakeHost(nil))
if tempDir, err := ioutil.TempDir("/tmp", "kubelet_test."); err != nil {
t.Fatalf("can't make a temp rootdir: %v", err)
} else {

View File

@ -0,0 +1,140 @@
/*
Copyright 2014 Google Inc. All rights reserved.
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 sucess
// - 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
// 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 (
"errors"
"fmt"
"io/ioutil"
"path"
"strings"
"syscall"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/network"
utilexec "github.com/GoogleCloudPlatform/kubernetes/pkg/util/exec"
"github.com/golang/glog"
)
type execNetworkPlugin struct {
execName string
execPath string
host network.Host
}
const (
initCmd = "init"
setUpCmd = "setup"
tearDownCmd = "teardown"
execDir = "/usr/libexec/kubernetes/kubelet-plugins/net/exec/"
X_OK = 0x1
)
func ProbeNetworkPlugins() []network.NetworkPlugin {
return probeNetworkPluginsWithExecDir(execDir)
}
func probeNetworkPluginsWithExecDir(pluginDir string) []network.NetworkPlugin {
execPlugins := []network.NetworkPlugin{}
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) 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()
glog.V(5).Infof("Init 'exec' network plugin output: %s, %v", string(out), err)
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 syscall.Access(plugin.getExecutable(), X_OK) != nil {
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 dockertools.DockerID) error {
out, err := utilexec.New().Command(plugin.getExecutable(), setUpCmd, namespace, name, string(id)).CombinedOutput()
glog.V(5).Infof("SetUpPod 'exec' network plugin output: %s, %v", string(out), err)
return err
}
func (plugin *execNetworkPlugin) TearDownPod(namespace string, name string, id dockertools.DockerID) error {
out, err := utilexec.New().Command(plugin.getExecutable(), tearDownCmd, namespace, name, string(id)).CombinedOutput()
glog.V(5).Infof("TearDownPod 'exec' network plugin output: %s, %v", string(out), err)
return err
}

View File

@ -0,0 +1,179 @@
// +build linux
/*
Copyright 2014 Google Inc. All rights reserved.
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 (
"fmt"
"io/ioutil"
"math/rand"
"os"
"path"
"testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/network"
)
// The temp dir where test plugins will be stored.
const testPluginPath = "/tmp/fake/plugins/net"
func installPluginUnderTest(t *testing.T, vendorName string, plugName string) {
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: %v", err)
}
pluginExec := path.Join(pluginDir, plugName)
f, err := os.Create(pluginExec)
if err != nil {
t.Errorf("Failed to install plugin")
}
err = f.Chmod(0777)
if err != nil {
t.Errorf("Failed to set exec perms on plugin")
}
writeStr := fmt.Sprintf("#!/bin/bash\necho -n $@ &> %s", path.Join(pluginDir, plugName+".out"))
_, err = f.WriteString(writeStr)
if err != nil {
t.Errorf("Failed to write plugin exec")
}
f.Close()
}
func tearDownPlugin(plugName string) {
err := os.RemoveAll(testPluginPath)
if err != nil {
fmt.Printf("Error in cleaning up test: %v", err)
}
}
func TestSelectPlugin(t *testing.T) {
// install some random plugin under testPluginPath
pluginName := fmt.Sprintf("test%d", rand.Intn(1000))
defer tearDownPlugin(pluginName)
installPluginUnderTest(t, "", pluginName)
plug, err := network.InitNetworkPlugin(probeNetworkPluginsWithExecDir(testPluginPath), pluginName, network.NewFakeHost(nil))
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) {
// install some random plugin under testPluginPath
pluginName := fmt.Sprintf("test%d", rand.Intn(1000))
defer tearDownPlugin(pluginName)
vendor := "mycompany"
installPluginUnderTest(t, vendor, pluginName)
vendoredPluginName := fmt.Sprintf("%s/%s", vendor, pluginName)
plug, err := network.InitNetworkPlugin(probeNetworkPluginsWithExecDir(testPluginPath), vendoredPluginName, network.NewFakeHost(nil))
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) {
// install some random plugin under testPluginPath
pluginName := fmt.Sprintf("test%d", rand.Intn(1000))
defer tearDownPlugin(pluginName)
installPluginUnderTest(t, "", pluginName)
wrongPlugin := "abcd"
plug, err := network.InitNetworkPlugin(probeNetworkPluginsWithExecDir(testPluginPath), wrongPlugin, network.NewFakeHost(nil))
if plug != nil || err == nil {
t.Errorf("Expected to see an error. Wrong plugin selected.")
}
}
func TestPluginValidation(t *testing.T) {
pluginName := fmt.Sprintf("test%d", rand.Intn(1000))
defer tearDownPlugin(pluginName)
installPluginUnderTest(t, "", pluginName)
// 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(probeNetworkPluginsWithExecDir(testPluginPath), pluginName, network.NewFakeHost(nil))
if err == nil {
// we expected an error here because validation would have failed
t.Errorf("Expected non-nil value.")
}
}
func TestPluginSetupHook(t *testing.T) {
pluginName := fmt.Sprintf("test%d", rand.Intn(1000))
defer tearDownPlugin(pluginName)
installPluginUnderTest(t, "", pluginName)
plug, err := network.InitNetworkPlugin(probeNetworkPluginsWithExecDir(testPluginPath), pluginName, network.NewFakeHost(nil))
err = plug.SetUpPod("podNamespace", "podName", "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) {
pluginName := fmt.Sprintf("test%d", rand.Intn(1000))
defer tearDownPlugin(pluginName)
installPluginUnderTest(t, "", pluginName)
plug, err := network.InitNetworkPlugin(probeNetworkPluginsWithExecDir(testPluginPath), pluginName, network.NewFakeHost(nil))
err = plug.TearDownPod("podNamespace", "podName", "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))
}
}

View File

@ -0,0 +1,122 @@
/*
Copyright 2014 Google Inc. All rights reserved.
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"
"strings"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util/errors"
"github.com/golang/glog"
)
const DefaultPluginName = "kubernetes.io/no-op"
// 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) error
// Name returns the plugin's name. This will be used when searching
// for a plugin by name, e.g.
Name() string
// 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.
SetUpPod(namespace string, name string, podInfraContainerID dockertools.DockerID) error
// TearDownPod is the method called before a pod's infra container will be deleted
TearDownPod(namespace string, name string, podInfraContainerID dockertools.DockerID) error
}
// Host is an interface that plugins can use to access the kubelet.
type Host interface {
// Get the pod structure by its name, namespace
GetPodByName(namespace, name string) (*api.Pod, bool)
// GetKubeClient returns a client interface
GetKubeClient() client.Interface
}
// InitNetworkPlugin inits the plugin that matches networkPluginName. Plugins must have unique names.
func InitNetworkPlugin(plugins []NetworkPlugin, networkPluginName string, host Host) (NetworkPlugin, error) {
if networkPluginName == "" {
// default to the no_op plugin
plug := &noopNetworkPlugin{}
return plug, nil
}
pluginMap := map[string]NetworkPlugin{}
allErrs := []error{}
for _, plugin := range plugins {
name := plugin.Name()
if !util.IsQualifiedName(name) {
allErrs = append(allErrs, fmt.Errorf("network plugin has invalid name: %#v", plugin))
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)
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, errors.NewAggregate(allErrs)
}
func UnescapePluginName(in string) string {
return strings.Replace(in, "~", "/", -1)
}
type noopNetworkPlugin struct {
}
func (plugin *noopNetworkPlugin) Init(host Host) error {
return nil
}
func (plugin *noopNetworkPlugin) Name() string {
return DefaultPluginName
}
func (plugin *noopNetworkPlugin) SetUpPod(namespace string, name string, id dockertools.DockerID) error {
return nil
}
func (plugin *noopNetworkPlugin) TearDownPod(namespace string, name string, id dockertools.DockerID) error {
return nil
}

View File

@ -0,0 +1,35 @@
/*
Copyright 2014 Google Inc. All rights reserved.
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"
)
func TestSelectDefaultPlugin(t *testing.T) {
all_plugins := []NetworkPlugin{}
plug, err := InitNetworkPlugin(all_plugins, "", NewFakeHost(nil))
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())
}
}

View File

@ -0,0 +1,42 @@
/*
Copyright 2014 Google Inc. All rights reserved.
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
// helper for testing plugins
// a fake host is created here that can be used by plugins for testing
import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
)
type fakeNetworkHost struct {
kubeClient client.Interface
}
func NewFakeHost(kubeClient client.Interface) *fakeNetworkHost {
host := &fakeNetworkHost{kubeClient: kubeClient}
return host
}
func (fnh *fakeNetworkHost) GetPodByName(name, namespace string) (*api.Pod, bool) {
return nil, false
}
func (fnh *fakeNetworkHost) GetKubeClient() client.Interface {
return nil
}

36
pkg/kubelet/networks.go Normal file
View File

@ -0,0 +1,36 @@
/*
Copyright 2014 Google Inc. All rights reserved.
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 kubelet
import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
)
// This just exports required functions from kubelet proper, for use by network
// plugins.
type networkHost struct {
kubelet *Kubelet
}
func (nh *networkHost) GetPodByName(name, namespace string) (*api.Pod, bool) {
return nh.kubelet.GetPodByName(name, namespace)
}
func (nh *networkHost) GetKubeClient() client.Interface {
return nh.kubelet.kubeClient
}

View File

@ -26,6 +26,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/record"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/cadvisor"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/dockertools"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/network"
docker "github.com/fsouza/go-dockerclient"
cadvisorApi "github.com/google/cadvisor/info/v1"
)
@ -78,6 +79,7 @@ func TestRunOnce(t *testing.T) {
cadvisor: cadvisor,
}
kb.networkPlugin, _ = network.InitNetworkPlugin([]network.NetworkPlugin{}, "", network.NewFakeHost(nil))
if err := kb.setupDataDirs(); err != nil {
t.Errorf("Failed to init data dirs: %v", err)
}