Commit 2c103af2 authored by Justin Santa Barbara's avatar Justin Santa Barbara

Create testable implementation of sysctl

This is so we can test kubenet Init, which calls sysctl
parent 5d25bfff
...@@ -38,7 +38,7 @@ var readOnlySysFSError = errors.New("ReadOnlySysFS") ...@@ -38,7 +38,7 @@ var readOnlySysFSError = errors.New("ReadOnlySysFS")
func (realConntracker) SetMax(max int) error { func (realConntracker) SetMax(max int) error {
glog.Infof("Setting nf_conntrack_max to %d", max) glog.Infof("Setting nf_conntrack_max to %d", max)
if err := sysctl.SetSysctl("net/netfilter/nf_conntrack_max", max); err != nil { if err := sysctl.New().SetSysctl("net/netfilter/nf_conntrack_max", max); err != nil {
return err return err
} }
// sysfs is expected to be mounted as 'rw'. However, it may be unexpectedly mounted as // sysfs is expected to be mounted as 'rw'. However, it may be unexpectedly mounted as
...@@ -60,7 +60,7 @@ func (realConntracker) SetMax(max int) error { ...@@ -60,7 +60,7 @@ func (realConntracker) SetMax(max int) error {
func (realConntracker) SetTCPEstablishedTimeout(seconds int) error { func (realConntracker) SetTCPEstablishedTimeout(seconds int) error {
glog.Infof("Setting nf_conntrack_tcp_timeout_established to %d", seconds) glog.Infof("Setting nf_conntrack_tcp_timeout_established to %d", seconds)
return sysctl.SetSysctl("net/netfilter/nf_conntrack_tcp_timeout_established", seconds) return sysctl.New().SetSysctl("net/netfilter/nf_conntrack_tcp_timeout_established", seconds)
} }
// isSysFSWritable checks /proc/mounts to see whether sysfs is 'rw' or not. // isSysFSWritable checks /proc/mounts to see whether sysfs is 'rw' or not.
......
...@@ -47,6 +47,7 @@ import ( ...@@ -47,6 +47,7 @@ import (
nodeutil "k8s.io/kubernetes/pkg/util/node" nodeutil "k8s.io/kubernetes/pkg/util/node"
"k8s.io/kubernetes/pkg/util/oom" "k8s.io/kubernetes/pkg/util/oom"
"k8s.io/kubernetes/pkg/util/resourcecontainer" "k8s.io/kubernetes/pkg/util/resourcecontainer"
utilsysctl "k8s.io/kubernetes/pkg/util/sysctl"
"k8s.io/kubernetes/pkg/util/wait" "k8s.io/kubernetes/pkg/util/wait"
"github.com/golang/glog" "github.com/golang/glog"
...@@ -204,7 +205,7 @@ func NewProxyServerDefault(config *options.ProxyServerConfig) (*ProxyServer, err ...@@ -204,7 +205,7 @@ func NewProxyServerDefault(config *options.ProxyServerConfig) (*ProxyServer, err
// IPTablesMasqueradeBit must be specified or defaulted. // IPTablesMasqueradeBit must be specified or defaulted.
return nil, fmt.Errorf("Unable to read IPTablesMasqueradeBit from config") return nil, fmt.Errorf("Unable to read IPTablesMasqueradeBit from config")
} }
proxierIptables, err := iptables.NewProxier(iptInterface, execer, config.IPTablesSyncPeriod.Duration, config.MasqueradeAll, int(*config.IPTablesMasqueradeBit), config.ClusterCIDR, hostname, getNodeIP(client, hostname)) proxierIptables, err := iptables.NewProxier(iptInterface, utilsysctl.New(), execer, config.IPTablesSyncPeriod.Duration, config.MasqueradeAll, int(*config.IPTablesMasqueradeBit), config.ClusterCIDR, hostname, getNodeIP(client, hostname))
if err != nil { if err != nil {
glog.Fatalf("Unable to create proxier: %v", err) glog.Fatalf("Unable to create proxier: %v", err)
} }
......
...@@ -270,9 +270,11 @@ func setupKernelTunables(option KernelTunableBehavior) error { ...@@ -270,9 +270,11 @@ func setupKernelTunables(option KernelTunableBehavior) error {
utilsysctl.KernelPanicOnOops: utilsysctl.KernelPanicOnOopsAlways, utilsysctl.KernelPanicOnOops: utilsysctl.KernelPanicOnOopsAlways,
} }
sysctl := utilsysctl.New()
errList := []error{} errList := []error{}
for flag, expectedValue := range desiredState { for flag, expectedValue := range desiredState {
val, err := utilsysctl.GetSysctl(flag) val, err := sysctl.GetSysctl(flag)
if err != nil { if err != nil {
errList = append(errList, err) errList = append(errList, err)
continue continue
...@@ -288,7 +290,7 @@ func setupKernelTunables(option KernelTunableBehavior) error { ...@@ -288,7 +290,7 @@ func setupKernelTunables(option KernelTunableBehavior) error {
glog.V(2).Infof("Invalid kernel flag: %v, expected value: %v, actual value: %v", flag, expectedValue, val) glog.V(2).Infof("Invalid kernel flag: %v, expected value: %v, actual value: %v", flag, expectedValue, val)
case KernelTunableModify: case KernelTunableModify:
glog.V(2).Infof("Updating kernel flag: %v, expected value: %v, actual value: %v", flag, expectedValue, val) glog.V(2).Infof("Updating kernel flag: %v, expected value: %v, actual value: %v", flag, expectedValue, val)
err = utilsysctl.SetSysctl(flag, expectedValue) err = sysctl.SetSysctl(flag, expectedValue)
if err != nil { if err != nil {
errList = append(errList, err) errList = append(errList, err)
} }
......
...@@ -71,6 +71,7 @@ type kubenetNetworkPlugin struct { ...@@ -71,6 +71,7 @@ type kubenetNetworkPlugin struct {
hairpinMode componentconfig.HairpinMode hairpinMode componentconfig.HairpinMode
hostportHandler hostport.HostportHandler hostportHandler hostport.HostportHandler
iptables utiliptables.Interface iptables utiliptables.Interface
sysctl utilsysctl.Interface
// vendorDir is passed by kubelet network-plugin-dir parameter. // vendorDir is passed by kubelet network-plugin-dir parameter.
// kubenet will search for cni binaries in DefaultCNIDir first, then continue to vendorDir. // kubenet will search for cni binaries in DefaultCNIDir first, then continue to vendorDir.
vendorDir string vendorDir string
...@@ -115,7 +116,7 @@ func (plugin *kubenetNetworkPlugin) Init(host network.Host, hairpinMode componen ...@@ -115,7 +116,7 @@ func (plugin *kubenetNetworkPlugin) Init(host network.Host, hairpinMode componen
// was built-in, we simply ignore the error here. A better thing to do is // was built-in, we simply ignore the error here. A better thing to do is
// to check the kernel version in the future. // to check the kernel version in the future.
plugin.execer.Command("modprobe", "br-netfilter").CombinedOutput() plugin.execer.Command("modprobe", "br-netfilter").CombinedOutput()
err := utilsysctl.SetSysctl(sysctlBridgeCallIptables, 1) err := plugin.sysctl.SetSysctl(sysctlBridgeCallIptables, 1)
if err != nil { if err != nil {
glog.Warningf("can't set sysctl %s: %v", sysctlBridgeCallIptables, err) glog.Warningf("can't set sysctl %s: %v", sysctlBridgeCallIptables, err)
} }
......
...@@ -166,7 +166,7 @@ func (plugin *NoopNetworkPlugin) Init(host Host, hairpinMode componentconfig.Hai ...@@ -166,7 +166,7 @@ func (plugin *NoopNetworkPlugin) Init(host Host, hairpinMode componentconfig.Hai
// Ensure the netfilter module is loaded on kernel >= 3.18; previously // Ensure the netfilter module is loaded on kernel >= 3.18; previously
// it was built-in. // it was built-in.
utilexec.New().Command("modprobe", "br-netfilter").CombinedOutput() utilexec.New().Command("modprobe", "br-netfilter").CombinedOutput()
if err := utilsysctl.SetSysctl(sysctlBridgeCallIptables, 1); err != nil { if err := utilsysctl.New().SetSysctl(sysctlBridgeCallIptables, 1); err != nil {
glog.Warningf("can't set sysctl %s: %v", sysctlBridgeCallIptables, err) glog.Warningf("can't set sysctl %s: %v", sysctlBridgeCallIptables, err)
} }
......
...@@ -123,7 +123,7 @@ func (lkct LinuxKernelCompatTester) IsCompatible() error { ...@@ -123,7 +123,7 @@ func (lkct LinuxKernelCompatTester) IsCompatible() error {
// Check for the required sysctls. We don't care about the value, just // Check for the required sysctls. We don't care about the value, just
// that it exists. If this Proxier is chosen, we'll initialize it as we // that it exists. If this Proxier is chosen, we'll initialize it as we
// need. // need.
_, err := utilsysctl.GetSysctl(sysctlRouteLocalnet) _, err := utilsysctl.New().GetSysctl(sysctlRouteLocalnet)
return err return err
} }
...@@ -195,16 +195,16 @@ var _ proxy.ProxyProvider = &Proxier{} ...@@ -195,16 +195,16 @@ var _ proxy.ProxyProvider = &Proxier{}
// An error will be returned if iptables fails to update or acquire the initial lock. // An error will be returned if iptables fails to update or acquire the initial lock.
// Once a proxier is created, it will keep iptables up to date in the background and // Once a proxier is created, it will keep iptables up to date in the background and
// will not terminate if a particular iptables call fails. // will not terminate if a particular iptables call fails.
func NewProxier(ipt utiliptables.Interface, exec utilexec.Interface, syncPeriod time.Duration, masqueradeAll bool, masqueradeBit int, clusterCIDR string, hostname string, nodeIP net.IP) (*Proxier, error) { func NewProxier(ipt utiliptables.Interface, sysctl utilsysctl.Interface, exec utilexec.Interface, syncPeriod time.Duration, masqueradeAll bool, masqueradeBit int, clusterCIDR string, hostname string, nodeIP net.IP) (*Proxier, error) {
// Set the route_localnet sysctl we need for // Set the route_localnet sysctl we need for
if err := utilsysctl.SetSysctl(sysctlRouteLocalnet, 1); err != nil { if err := sysctl.SetSysctl(sysctlRouteLocalnet, 1); err != nil {
return nil, fmt.Errorf("can't set sysctl %s: %v", sysctlRouteLocalnet, err) return nil, fmt.Errorf("can't set sysctl %s: %v", sysctlRouteLocalnet, err)
} }
// Proxy needs br_netfilter and bridge-nf-call-iptables=1 when containers // Proxy needs br_netfilter and bridge-nf-call-iptables=1 when containers
// are connected to a Linux bridge (but not SDN bridges). Until most // are connected to a Linux bridge (but not SDN bridges). Until most
// plugins handle this, log when config is missing // plugins handle this, log when config is missing
if val, err := utilsysctl.GetSysctl(sysctlBridgeCallIptables); err == nil && val != 1 { if val, err := sysctl.GetSysctl(sysctlBridgeCallIptables); err == nil && val != 1 {
glog.Infof("missing br-netfilter module or unset sysctl br-nf-call-iptables; proxy may not work as intended") glog.Infof("missing br-netfilter module or unset sysctl br-nf-call-iptables; proxy may not work as intended")
} }
......
...@@ -37,8 +37,25 @@ const ( ...@@ -37,8 +37,25 @@ const (
KernelPanicRebootTimeout = 10 // seconds after a panic for the kernel to reboot KernelPanicRebootTimeout = 10 // seconds after a panic for the kernel to reboot
) )
// An injectable interface for running sysctl commands.
type Interface interface {
// GetSysctl returns the value for the specified sysctl setting
GetSysctl(sysctl string) (int, error)
// SetSysctl modifies the specified sysctl flag to the new value
SetSysctl(sysctl string, newVal int) error
}
// New returns a new Interface for accessing sysctl
func New() Interface {
return &procSysctl{}
}
// procSysctl implements Interface by reading and writing files under /proc/sys
type procSysctl struct {
}
// GetSysctl returns the value for the specified sysctl setting // GetSysctl returns the value for the specified sysctl setting
func GetSysctl(sysctl string) (int, error) { func (_ *procSysctl) GetSysctl(sysctl string) (int, error) {
data, err := ioutil.ReadFile(path.Join(sysctlBase, sysctl)) data, err := ioutil.ReadFile(path.Join(sysctlBase, sysctl))
if err != nil { if err != nil {
return -1, err return -1, err
...@@ -51,6 +68,6 @@ func GetSysctl(sysctl string) (int, error) { ...@@ -51,6 +68,6 @@ func GetSysctl(sysctl string) (int, error) {
} }
// SetSysctl modifies the specified sysctl flag to the new value // SetSysctl modifies the specified sysctl flag to the new value
func SetSysctl(sysctl string, newVal int) error { func (_ *procSysctl) SetSysctl(sysctl string, newVal int) error {
return ioutil.WriteFile(path.Join(sysctlBase, sysctl), []byte(strconv.Itoa(newVal)), 0640) return ioutil.WriteFile(path.Join(sysctlBase, sysctl), []byte(strconv.Itoa(newVal)), 0640)
} }
/*
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 testing
import (
"k8s.io/kubernetes/pkg/util/sysctl"
"os"
)
// fake is a map-backed implementation of sysctl.Interface, for testing/mocking
type fake struct {
Settings map[string]int
}
func NewFake() *fake {
return &fake{
Settings: make(map[string]int),
}
}
// GetSysctl returns the value for the specified sysctl setting
func (m *fake) GetSysctl(sysctl string) (int, error) {
v, found := m.Settings[sysctl]
if !found {
return -1, os.ErrNotExist
}
return v, nil
}
// SetSysctl modifies the specified sysctl flag to the new value
func (m *fake) SetSysctl(sysctl string, newVal int) error {
m.Settings[sysctl] = newVal
return nil
}
var _ = sysctl.Interface(&fake{})
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment