mirror of https://github.com/k3s-io/k3s
commit
c2485a4056
|
@ -34,11 +34,22 @@ def ensure(name, cidr, mtu=1460):
|
|||
'''
|
||||
ret = {'name': name, 'changes': {}, 'result': False, 'comment': ''}
|
||||
|
||||
iptables_rule = {
|
||||
'table': 'nat',
|
||||
'chain': 'POSTROUTING',
|
||||
'rule': '-o eth0 -j MASQUERADE \! -d 10.0.0.0/8'
|
||||
}
|
||||
# This is a little hacky. I should probably import a real library for this
|
||||
# but this'll work for now.
|
||||
try:
|
||||
cidr_network = ipaddr.IPNetwork(cidr, strict=True)
|
||||
except Exception:
|
||||
raise salt.exceptions.SaltInvocationError(
|
||||
'Invalid CIDR \'{0}\''.format(cidr))
|
||||
|
||||
if cidr_network.version == 4:
|
||||
iptables_rule = {
|
||||
'table': 'nat',
|
||||
'chain': 'POSTROUTING',
|
||||
'rule': '-o eth0 -j MASQUERADE \! -d 10.0.0.0/8'
|
||||
}
|
||||
else:
|
||||
iptables_rule = None
|
||||
|
||||
def bridge_exists(name):
|
||||
'Determine if a bridge exists already.'
|
||||
|
@ -90,20 +101,15 @@ def ensure(name, cidr, mtu=1460):
|
|||
ret['details'] = {}
|
||||
# This module function is strange and returns True if the rule exists.
|
||||
# If not, it returns a string with the error from the call to iptables.
|
||||
ret['iptables_rule_exists'] = \
|
||||
__salt__['iptables.check'](**iptables_rule) == True
|
||||
if iptables_rule:
|
||||
ret['iptables_rule_exists'] = \
|
||||
__salt__['iptables.check'](**iptables_rule) == True
|
||||
else:
|
||||
ret['iptables_rule_exists'] = True
|
||||
return ret
|
||||
|
||||
# This is a little hacky. I should probably import a real library for this
|
||||
# but this'll work for now.
|
||||
try:
|
||||
cidr_network = ipaddr.IPv4Network(cidr, strict=True)
|
||||
except Exception:
|
||||
raise salt.exceptions.SaltInvocationError(
|
||||
'Invalid CIDR \'{0}\''.format(cidr))
|
||||
|
||||
desired_network = '{0}/{1}'.format(
|
||||
str(ipaddr.IPv4Address(cidr_network._ip + 1)),
|
||||
str(ipaddr.IPAddress(cidr_network._ip + 1)),
|
||||
str(cidr_network.prefixlen))
|
||||
|
||||
current_state = get_current_state()
|
||||
|
@ -147,7 +153,7 @@ def ensure(name, cidr, mtu=1460):
|
|||
__salt__['cmd.run'](
|
||||
'ip link set dev {0} up'.format(name))
|
||||
new_state = get_current_state()
|
||||
if not new_state['iptables_rule_exists']:
|
||||
if iptables_rule and not new_state['iptables_rule_exists']:
|
||||
__salt__['iptables.append'](**iptables_rule)
|
||||
new_state = get_current_state()
|
||||
|
||||
|
|
|
@ -1 +1,6 @@
|
|||
DOCKER_OPTS="--bridge cbr0 --iptables=false --ip-masq=false -r=false"
|
||||
{% if grains.docker_opts is defined %}
|
||||
{% set docker_opts = grains.docker_opts %}
|
||||
{% else %}
|
||||
{% set docker_opts = "" %}
|
||||
{% endif %}
|
||||
DOCKER_OPTS="{{docker_opts}} --bridge cbr0 --iptables=false --ip-masq=false -r=false"
|
||||
|
|
|
@ -100,8 +100,12 @@ func main() {
|
|||
}
|
||||
}
|
||||
|
||||
protocol := iptables.ProtocolIpv4
|
||||
if net.IP(bindAddress).To4() == nil {
|
||||
protocol = iptables.ProtocolIpv6
|
||||
}
|
||||
loadBalancer := proxy.NewLoadBalancerRR()
|
||||
proxier := proxy.NewProxier(loadBalancer, net.IP(bindAddress), iptables.New(exec.New()))
|
||||
proxier := proxy.NewProxier(loadBalancer, net.IP(bindAddress), iptables.New(exec.New(), protocol))
|
||||
// Wire proxier to handle changes to services
|
||||
serviceConfig.RegisterHandler(proxier)
|
||||
// And wire loadBalancer to handle changes to endpoints to services
|
||||
|
|
|
@ -532,8 +532,11 @@ func iptablesFlush(ipt iptables.Interface) error {
|
|||
}
|
||||
|
||||
// Used below.
|
||||
var zeroIP = net.ParseIP("0.0.0.0")
|
||||
var localhostIP = net.ParseIP("127.0.0.1")
|
||||
var zeroIPv4 = net.ParseIP("0.0.0.0")
|
||||
var localhostIPv4 = net.ParseIP("127.0.0.1")
|
||||
|
||||
var zeroIPv6 = net.ParseIP("::0")
|
||||
var localhostIPv6 = net.ParseIP("::1")
|
||||
|
||||
// Build a slice of iptables args for a portal rule.
|
||||
func iptablesPortalArgs(destIP net.IP, destPort int, protocol api.Protocol, proxyIP net.IP, proxyPort int, service string) []string {
|
||||
|
@ -561,10 +564,13 @@ func iptablesPortalArgs(destIP net.IP, destPort int, protocol api.Protocol, prox
|
|||
// Unfortunately, I don't know of any way to listen on some (N > 1)
|
||||
// interfaces but not ALL interfaces, short of doing it manually, and
|
||||
// this is simpler than that.
|
||||
if proxyIP.Equal(zeroIP) || proxyIP.Equal(localhostIP) {
|
||||
if proxyIP.Equal(zeroIPv4) || proxyIP.Equal(zeroIPv6) ||
|
||||
proxyIP.Equal(localhostIPv4) || proxyIP.Equal(localhostIPv6) {
|
||||
// TODO: Can we REDIRECT with IPv6?
|
||||
args = append(args, "-j", "REDIRECT", "--to-ports", fmt.Sprintf("%d", proxyPort))
|
||||
} else {
|
||||
args = append(args, "-j", "DNAT", "--to-destination", fmt.Sprintf("%s:%d", proxyIP.String(), proxyPort))
|
||||
// TODO: Can we DNAT with IPv6?
|
||||
args = append(args, "-j", "DNAT", "--to-destination", net.JoinHostPort(proxyIP.String(), strconv.Itoa(proxyPort)))
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
|
|
@ -94,6 +94,10 @@ func (fake *fakeIptables) DeleteRule(table iptables.Table, chain iptables.Chain,
|
|||
return nil
|
||||
}
|
||||
|
||||
func (fake *fakeIptables) IsIpv6() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
var tcpServerPort string
|
||||
var udpServerPort string
|
||||
|
||||
|
|
|
@ -18,17 +18,67 @@ package service
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
math_rand "math/rand"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
type ipAllocator struct {
|
||||
subnet *net.IPNet
|
||||
// TODO: This could be smarter, but for now a bitmap will suffice.
|
||||
lock sync.Mutex // protects 'used'
|
||||
used []byte // a bitmap of allocated IPs
|
||||
|
||||
subnet net.IPNet
|
||||
ipSpaceSize int64 // Size of subnet, or -1 if it does not fit in an int64
|
||||
used ipAddrSet
|
||||
randomAttempts int
|
||||
|
||||
random *math_rand.Rand
|
||||
}
|
||||
|
||||
type ipAddrSet struct {
|
||||
// We are pretty severely restricted in the types of things we can use as a key
|
||||
ips map[string]bool
|
||||
}
|
||||
|
||||
func (s *ipAddrSet) Init() {
|
||||
s.ips = map[string]bool{}
|
||||
}
|
||||
|
||||
// Adds to the ipAddrSet; returns true iff it was added (was not already in set)
|
||||
func (s *ipAddrSet) Size() int {
|
||||
return len(s.ips)
|
||||
}
|
||||
|
||||
func (s *ipAddrSet) Contains(ip net.IP) bool {
|
||||
key := ip.String()
|
||||
exists := s.ips[key]
|
||||
return exists
|
||||
}
|
||||
|
||||
// Adds to the ipAddrSet; returns true iff it was added (was not already in set)
|
||||
func (s *ipAddrSet) Add(ip net.IP) bool {
|
||||
key := ip.String()
|
||||
exists := s.ips[key]
|
||||
if exists {
|
||||
return false
|
||||
}
|
||||
s.ips[key] = true
|
||||
return true
|
||||
}
|
||||
|
||||
// Removes from the ipAddrSet; returns true iff it was removed (was already in set)
|
||||
func (s *ipAddrSet) Remove(ip net.IP) bool {
|
||||
key := ip.String()
|
||||
exists := s.ips[key]
|
||||
if !exists {
|
||||
return false
|
||||
}
|
||||
delete(s.ips, key)
|
||||
// TODO: We probably should add this IP to an 'embargo' list for a limited amount of time
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// The smallest number of IPs we accept.
|
||||
|
@ -40,20 +90,42 @@ func newIPAllocator(subnet *net.IPNet) *ipAllocator {
|
|||
return nil
|
||||
}
|
||||
|
||||
seed := time.Now().UTC().UnixNano()
|
||||
r := math_rand.New(math_rand.NewSource(seed))
|
||||
|
||||
ipSpaceSize := int64(-1)
|
||||
ones, bits := subnet.Mask.Size()
|
||||
// TODO: some settings with IPv6 address could cause this to take
|
||||
// an excessive amount of memory.
|
||||
numIps := 1 << uint(bits-ones)
|
||||
if numIps < minIPSpace {
|
||||
glog.Errorf("IPAllocator requires at least %d IPs", minIPSpace)
|
||||
return nil
|
||||
if (bits - ones) < 63 {
|
||||
ipSpaceSize = int64(1) << uint(bits-ones)
|
||||
|
||||
if ipSpaceSize < minIPSpace {
|
||||
glog.Errorf("IPAllocator requires at least %d IPs", minIPSpace)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
ipa := &ipAllocator{
|
||||
subnet: subnet,
|
||||
used: make([]byte, numIps/8),
|
||||
subnet: *subnet,
|
||||
ipSpaceSize: ipSpaceSize,
|
||||
random: r,
|
||||
randomAttempts: 1000,
|
||||
}
|
||||
ipa.used[0] = 0x01 // block the network addr
|
||||
ipa.used[(numIps/8)-1] = 0x80 // block the broadcast addr
|
||||
ipa.used.Init()
|
||||
|
||||
zero := make(net.IP, len(subnet.IP), len(subnet.IP))
|
||||
for i := 0; i < len(subnet.IP); i++ {
|
||||
zero[i] = subnet.IP[i] & subnet.Mask[i]
|
||||
}
|
||||
ipa.used.Add(zero) // block the zero addr
|
||||
|
||||
ipa.used.Add(subnet.IP) // block the network addr
|
||||
|
||||
broadcast := make(net.IP, len(subnet.IP), len(subnet.IP))
|
||||
for i := 0; i < len(subnet.IP); i++ {
|
||||
broadcast[i] = subnet.IP[i] | ^subnet.Mask[i]
|
||||
}
|
||||
ipa.used.Add(broadcast) // block the broadcast addr
|
||||
|
||||
return ipa
|
||||
}
|
||||
|
||||
|
@ -65,13 +137,11 @@ func (ipa *ipAllocator) Allocate(ip net.IP) error {
|
|||
if !ipa.subnet.Contains(ip) {
|
||||
return fmt.Errorf("IP %s does not fall within subnet %s", ip, ipa.subnet)
|
||||
}
|
||||
offset := ipSub(ip, ipa.subnet.IP)
|
||||
i := offset / 8
|
||||
m := byte(1 << byte(offset%8))
|
||||
if ipa.used[i]&m != 0 {
|
||||
|
||||
if !ipa.used.Add(ip) {
|
||||
return fmt.Errorf("IP %s is already allocated", ip)
|
||||
}
|
||||
ipa.used[i] |= m
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -80,33 +150,48 @@ func (ipa *ipAllocator) AllocateNext() (net.IP, error) {
|
|||
ipa.lock.Lock()
|
||||
defer ipa.lock.Unlock()
|
||||
|
||||
for i := range ipa.used {
|
||||
if ipa.used[i] != 0xff {
|
||||
freeMask := ^ipa.used[i]
|
||||
nextBit, err := ffs(freeMask)
|
||||
if err != nil {
|
||||
// If this happens, something really weird is going on.
|
||||
glog.Errorf("ffs(%#x) had an unexpected error: %s", freeMask, err)
|
||||
return nil, err
|
||||
}
|
||||
ipa.used[i] |= 1 << nextBit
|
||||
offset := (i * 8) + int(nextBit)
|
||||
ip := ipAdd(ipa.subnet.IP, offset)
|
||||
if int64(ipa.used.Size()) == ipa.ipSpaceSize {
|
||||
return nil, fmt.Errorf("can't find a free IP in %s", ipa.subnet)
|
||||
}
|
||||
|
||||
// Try randomly first
|
||||
for i := 0; i < ipa.randomAttempts; i++ {
|
||||
ip := ipa.createRandomIp()
|
||||
|
||||
if ipa.used.Add(ip) {
|
||||
return ip, nil
|
||||
}
|
||||
}
|
||||
|
||||
// If that doesn't work, try a linear search
|
||||
ip := copyIP(ipa.subnet.IP)
|
||||
for ipa.subnet.Contains(ip) {
|
||||
ip = ipAdd(ip, 1)
|
||||
if ipa.used.Add(ip) {
|
||||
return ip, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("can't find a free IP in %s", ipa.subnet)
|
||||
}
|
||||
|
||||
// This is a really dumb implementation of find-first-set-bit.
|
||||
func ffs(val byte) (uint, error) {
|
||||
if val == 0 {
|
||||
return 0, fmt.Errorf("Can't find-first-set on 0")
|
||||
func (ipa *ipAllocator) createRandomIp() net.IP {
|
||||
ip := ipa.subnet.IP
|
||||
mask := ipa.subnet.Mask
|
||||
n := len(ip)
|
||||
|
||||
randomIp := make(net.IP, n, n)
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
if mask[i] == 0xff {
|
||||
randomIp[i] = ipa.subnet.IP[i]
|
||||
} else {
|
||||
b := byte(ipa.random.Intn(256))
|
||||
randomIp[i] = (ipa.subnet.IP[i] & mask[i]) | (b &^ mask[i])
|
||||
}
|
||||
}
|
||||
i := uint(0)
|
||||
for ; i < 8 && (val&(1<<i) == 0); i++ {
|
||||
}
|
||||
return i, nil
|
||||
|
||||
return randomIp
|
||||
}
|
||||
|
||||
// Add an offset to an IP address - used for joining network addr and host addr parts.
|
||||
|
@ -123,33 +208,6 @@ func ipAdd(ip net.IP, offset int) net.IP {
|
|||
return out
|
||||
}
|
||||
|
||||
// Subtract two IPs, returning the difference as an offset - used or splitting an IP into
|
||||
// network addr and host addr parts.
|
||||
func ipSub(lhs, rhs net.IP) int {
|
||||
// If they are not the same length, normalize them. Make copies because net.IP is
|
||||
// a slice underneath. Sneaky sneaky.
|
||||
lhs = simplifyIP(lhs)
|
||||
rhs = simplifyIP(rhs)
|
||||
if len(lhs) != len(rhs) {
|
||||
lhs = copyIP(lhs).To16()
|
||||
rhs = copyIP(rhs).To16()
|
||||
}
|
||||
offset := 0
|
||||
borrow := 0
|
||||
// Loop from most-significant to least.
|
||||
for i := range lhs {
|
||||
offset <<= 8
|
||||
result := (int(lhs[i]) - borrow) - int(rhs[i])
|
||||
if result < 0 {
|
||||
borrow = 1
|
||||
} else {
|
||||
borrow = 0
|
||||
}
|
||||
offset += result
|
||||
}
|
||||
return offset
|
||||
}
|
||||
|
||||
// Get the optimal slice for an IP. IPv4 addresses will come back in a 4 byte slice. IPv6
|
||||
// addresses will come back in a 16 byte slice. Non-IP arguments will produce nil.
|
||||
func simplifyIP(in net.IP) net.IP {
|
||||
|
@ -176,9 +234,6 @@ func (ipa *ipAllocator) Release(ip net.IP) error {
|
|||
if !ipa.subnet.Contains(ip) {
|
||||
return fmt.Errorf("IP %s does not fall within subnet %s", ip, ipa.subnet)
|
||||
}
|
||||
offset := ipSub(ip, ipa.subnet.IP)
|
||||
i := offset / 8
|
||||
m := byte(1 << byte(offset%8))
|
||||
ipa.used[i] &^= m
|
||||
ipa.used.Remove(ip)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -36,13 +36,16 @@ func TestNew(t *testing.T) {
|
|||
if ipa == nil {
|
||||
t.Errorf("expected non-nil")
|
||||
}
|
||||
if len(ipa.used) != 128 { // a /22 has 1024 IPs, 8 per byte = 128
|
||||
t.Errorf("wrong size for ipa.used")
|
||||
if ipa.ipSpaceSize != 1024 {
|
||||
t.Errorf("wrong size for ipa.ipSpaceSize")
|
||||
}
|
||||
if ipa.used[0] != 0x01 {
|
||||
if ipa.used.Size() != 2 {
|
||||
t.Errorf("wrong size() for ipa.used")
|
||||
}
|
||||
if !ipa.used.Contains(net.ParseIP("93.76.0.0")) {
|
||||
t.Errorf("network address was not reserved")
|
||||
}
|
||||
if ipa.used[127] != 0x80 {
|
||||
if !ipa.used.Contains(net.ParseIP("93.76.3.255")) {
|
||||
t.Errorf("broadcast address was not reserved")
|
||||
}
|
||||
}
|
||||
|
@ -68,6 +71,9 @@ func TestAllocateNext(t *testing.T) {
|
|||
_, ipnet, _ := net.ParseCIDR("93.76.0.0/22")
|
||||
ipa := newIPAllocator(ipnet)
|
||||
|
||||
// Turn off random allocation attempts, so we just allocate in sequence
|
||||
ipa.randomAttempts = 0
|
||||
|
||||
ip1, err := ipa.AllocateNext()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
|
@ -128,6 +134,8 @@ func TestRelease(t *testing.T) {
|
|||
_, ipnet, _ := net.ParseCIDR("93.76.0.0/24")
|
||||
ipa := newIPAllocator(ipnet)
|
||||
|
||||
ipa.randomAttempts = 0
|
||||
|
||||
err := ipa.Release(net.ParseIP("1.2.3.4"))
|
||||
if err == nil {
|
||||
t.Errorf("Expected an error")
|
||||
|
@ -172,31 +180,6 @@ func TestRelease(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestFFS(t *testing.T) {
|
||||
_, err := ffs(0)
|
||||
if err == nil {
|
||||
t.Errorf("Expected error")
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
value byte
|
||||
expected uint
|
||||
}{
|
||||
{0x01, 0}, {0x02, 1}, {0x04, 2}, {0x08, 3},
|
||||
{0x10, 4}, {0x20, 5}, {0x40, 6}, {0x80, 7},
|
||||
{0x22, 1}, {0xa0, 5}, {0xfe, 1}, {0xff, 0},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
r, err := ffs(tc.value)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if r != tc.expected {
|
||||
t.Errorf("Expected %d, got %d", tc.expected, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIPAdd(t *testing.T) {
|
||||
testCases := []struct {
|
||||
ip string
|
||||
|
@ -223,31 +206,6 @@ func TestIPAdd(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestIPSub(t *testing.T) {
|
||||
testCases := []struct {
|
||||
lhs string
|
||||
rhs string
|
||||
expected int
|
||||
}{
|
||||
{"1.2.3.0", "1.2.3.0", 0},
|
||||
{"1.2.3.1", "1.2.3.0", 1},
|
||||
{"1.2.3.255", "1.2.3.0", 255},
|
||||
{"1.2.4.0", "1.2.3.0", 256},
|
||||
{"1.2.4.0", "1.2.3.255", 1},
|
||||
{"1.2.4.1", "1.2.3.0", 257},
|
||||
{"1.3.3.0", "1.2.3.0", 65536},
|
||||
{"1.2.3.5", "1.2.3.4", 1},
|
||||
{"0.0.0.0", "0.0.0.1", -1},
|
||||
{"0.0.1.0", "0.0.0.1", 255},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
r := ipSub(net.ParseIP(tc.lhs), net.ParseIP(tc.rhs))
|
||||
if r != tc.expected {
|
||||
t.Errorf("Expected %v, got %v", tc.expected, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyIP(t *testing.T) {
|
||||
ip1 := net.ParseIP("1.2.3.4")
|
||||
ip2 := copyIP(ip1)
|
||||
|
|
|
@ -44,6 +44,8 @@ func TestServiceRegistryCreate(t *testing.T) {
|
|||
fakeCloud := &cloud.FakeCloud{}
|
||||
machines := []string{"foo", "bar", "baz"}
|
||||
storage := NewREST(registry, fakeCloud, registrytest.NewMinionRegistry(machines, api.NodeResources{}), makeIPNet(t))
|
||||
storage.portalMgr.randomAttempts = 0
|
||||
|
||||
svc := &api.Service{
|
||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||
Spec: api.ServiceSpec{
|
||||
|
@ -455,6 +457,7 @@ func TestServiceRegistryIPAllocation(t *testing.T) {
|
|||
fakeCloud := &cloud.FakeCloud{}
|
||||
machines := []string{"foo", "bar", "baz"}
|
||||
rest := NewREST(registry, fakeCloud, registrytest.NewMinionRegistry(machines, api.NodeResources{}), makeIPNet(t))
|
||||
rest.portalMgr.randomAttempts = 0
|
||||
|
||||
svc1 := &api.Service{
|
||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||
|
@ -513,6 +516,7 @@ func TestServiceRegistryIPReallocation(t *testing.T) {
|
|||
fakeCloud := &cloud.FakeCloud{}
|
||||
machines := []string{"foo", "bar", "baz"}
|
||||
rest := NewREST(registry, fakeCloud, registrytest.NewMinionRegistry(machines, api.NodeResources{}), makeIPNet(t))
|
||||
rest.portalMgr.randomAttempts = 0
|
||||
|
||||
svc1 := &api.Service{
|
||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||
|
@ -559,6 +563,7 @@ func TestServiceRegistryIPUpdate(t *testing.T) {
|
|||
fakeCloud := &cloud.FakeCloud{}
|
||||
machines := []string{"foo", "bar", "baz"}
|
||||
rest := NewREST(registry, fakeCloud, registrytest.NewMinionRegistry(machines, api.NodeResources{}), makeIPNet(t))
|
||||
rest.portalMgr.randomAttempts = 0
|
||||
|
||||
svc := &api.Service{
|
||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||
|
@ -613,6 +618,7 @@ func TestServiceRegistryIPExternalLoadBalancer(t *testing.T) {
|
|||
fakeCloud := &cloud.FakeCloud{}
|
||||
machines := []string{"foo", "bar", "baz"}
|
||||
rest := NewREST(registry, fakeCloud, registrytest.NewMinionRegistry(machines, api.NodeResources{}), makeIPNet(t))
|
||||
rest.portalMgr.randomAttempts = 0
|
||||
|
||||
svc := &api.Service{
|
||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||
|
@ -642,6 +648,7 @@ func TestServiceRegistryIPReloadFromStorage(t *testing.T) {
|
|||
fakeCloud := &cloud.FakeCloud{}
|
||||
machines := []string{"foo", "bar", "baz"}
|
||||
rest1 := NewREST(registry, fakeCloud, registrytest.NewMinionRegistry(machines, api.NodeResources{}), makeIPNet(t))
|
||||
rest1.portalMgr.randomAttempts = 0
|
||||
|
||||
svc := &api.Service{
|
||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||
|
@ -665,6 +672,7 @@ func TestServiceRegistryIPReloadFromStorage(t *testing.T) {
|
|||
|
||||
// This will reload from storage, finding the previous 2
|
||||
rest2 := NewREST(registry, fakeCloud, registrytest.NewMinionRegistry(machines, api.NodeResources{}), makeIPNet(t))
|
||||
rest2.portalMgr.randomAttempts = 0
|
||||
|
||||
svc = &api.Service{
|
||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||
|
|
|
@ -34,8 +34,17 @@ type Interface interface {
|
|||
EnsureRule(table Table, chain Chain, args ...string) (bool, error)
|
||||
// DeleteRule checks if the specified rule is present and, if so, deletes it.
|
||||
DeleteRule(table Table, chain Chain, args ...string) error
|
||||
// IsIpv6 returns true if this is managing ipv6 tables
|
||||
IsIpv6() bool
|
||||
}
|
||||
|
||||
type Protocol bool
|
||||
|
||||
const (
|
||||
ProtocolIpv4 Protocol = false
|
||||
ProtocolIpv6 Protocol = true
|
||||
)
|
||||
|
||||
type Table string
|
||||
|
||||
const (
|
||||
|
@ -51,13 +60,14 @@ const (
|
|||
|
||||
// runner implements Interface in terms of exec("iptables").
|
||||
type runner struct {
|
||||
mu sync.Mutex
|
||||
exec utilexec.Interface
|
||||
mu sync.Mutex
|
||||
exec utilexec.Interface
|
||||
protocol Protocol
|
||||
}
|
||||
|
||||
// New returns a new Interface which will exec iptables.
|
||||
func New(exec utilexec.Interface) Interface {
|
||||
return &runner{exec: exec}
|
||||
func New(exec utilexec.Interface, protocol Protocol) Interface {
|
||||
return &runner{exec: exec, protocol: protocol}
|
||||
}
|
||||
|
||||
// EnsureChain is part of Interface.
|
||||
|
@ -135,8 +145,20 @@ func (runner *runner) DeleteRule(table Table, chain Chain, args ...string) error
|
|||
return nil
|
||||
}
|
||||
|
||||
func (runner *runner) IsIpv6() bool {
|
||||
return runner.protocol == ProtocolIpv6
|
||||
}
|
||||
|
||||
func (runner *runner) iptablesCommand() string {
|
||||
if runner.IsIpv6() {
|
||||
return "ip6tables"
|
||||
} else {
|
||||
return "iptables"
|
||||
}
|
||||
}
|
||||
|
||||
func (runner *runner) run(op operation, args []string) ([]byte, error) {
|
||||
const iptablesCmd = "iptables"
|
||||
iptablesCmd := runner.iptablesCommand()
|
||||
|
||||
fullArgs := append([]string{string(op)}, args...)
|
||||
glog.V(1).Infof("running iptables %s %v", string(op), args)
|
||||
|
|
|
@ -23,7 +23,17 @@ import (
|
|||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util/exec"
|
||||
)
|
||||
|
||||
func TestEnsureChain(t *testing.T) {
|
||||
func getIptablesCommand(protocol Protocol) string {
|
||||
if protocol == ProtocolIpv4 {
|
||||
return "iptables"
|
||||
}
|
||||
if protocol == ProtocolIpv6 {
|
||||
return "ip6tables"
|
||||
}
|
||||
panic("Unknown protocol")
|
||||
}
|
||||
|
||||
func testEnsureChain(t *testing.T, protocol Protocol) {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
// Success.
|
||||
|
@ -41,7 +51,7 @@ func TestEnsureChain(t *testing.T) {
|
|||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
runner := New(&fexec)
|
||||
runner := New(&fexec, protocol)
|
||||
// Success.
|
||||
exists, err := runner.EnsureChain(TableNAT, Chain("FOOBAR"))
|
||||
if err != nil {
|
||||
|
@ -53,7 +63,8 @@ func TestEnsureChain(t *testing.T) {
|
|||
if fcmd.CombinedOutputCalls != 1 {
|
||||
t.Errorf("expected 1 CombinedOutput() call, got %d", fcmd.CombinedOutputCalls)
|
||||
}
|
||||
if !util.NewStringSet(fcmd.CombinedOutputLog[0]...).HasAll("iptables", "-t", "nat", "-N", "FOOBAR") {
|
||||
cmd := getIptablesCommand(protocol)
|
||||
if !util.NewStringSet(fcmd.CombinedOutputLog[0]...).HasAll(cmd, "-t", "nat", "-N", "FOOBAR") {
|
||||
t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[0])
|
||||
}
|
||||
// Exists.
|
||||
|
@ -71,6 +82,14 @@ func TestEnsureChain(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestEnsureChainIpv4(t *testing.T) {
|
||||
testEnsureChain(t, ProtocolIpv4)
|
||||
}
|
||||
|
||||
func TestEnsureChainIpv6(t *testing.T) {
|
||||
testEnsureChain(t, ProtocolIpv6)
|
||||
}
|
||||
|
||||
func TestFlushChain(t *testing.T) {
|
||||
fcmd := exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
|
@ -86,7 +105,7 @@ func TestFlushChain(t *testing.T) {
|
|||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
runner := New(&fexec)
|
||||
runner := New(&fexec, ProtocolIpv4)
|
||||
// Success.
|
||||
err := runner.FlushChain(TableNAT, Chain("FOOBAR"))
|
||||
if err != nil {
|
||||
|
@ -118,7 +137,7 @@ func TestEnsureRuleAlreadyExists(t *testing.T) {
|
|||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
runner := New(&fexec)
|
||||
runner := New(&fexec, ProtocolIpv4)
|
||||
exists, err := runner.EnsureRule(TableNAT, ChainOutput, "abc", "123")
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %+v", err)
|
||||
|
@ -150,7 +169,7 @@ func TestEnsureRuleNew(t *testing.T) {
|
|||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
runner := New(&fexec)
|
||||
runner := New(&fexec, ProtocolIpv4)
|
||||
exists, err := runner.EnsureRule(TableNAT, ChainOutput, "abc", "123")
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %+v", err)
|
||||
|
@ -179,7 +198,7 @@ func TestEnsureRuleErrorChecking(t *testing.T) {
|
|||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
runner := New(&fexec)
|
||||
runner := New(&fexec, ProtocolIpv4)
|
||||
_, err := runner.EnsureRule(TableNAT, ChainOutput, "abc", "123")
|
||||
if err == nil {
|
||||
t.Errorf("expected failure")
|
||||
|
@ -205,7 +224,7 @@ func TestEnsureRuleErrorCreating(t *testing.T) {
|
|||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
runner := New(&fexec)
|
||||
runner := New(&fexec, ProtocolIpv4)
|
||||
_, err := runner.EnsureRule(TableNAT, ChainOutput, "abc", "123")
|
||||
if err == nil {
|
||||
t.Errorf("expected failure")
|
||||
|
@ -228,7 +247,7 @@ func TestDeleteRuleAlreadyExists(t *testing.T) {
|
|||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
runner := New(&fexec)
|
||||
runner := New(&fexec, ProtocolIpv4)
|
||||
err := runner.DeleteRule(TableNAT, ChainOutput, "abc", "123")
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %+v", err)
|
||||
|
@ -257,7 +276,7 @@ func TestDeleteRuleNew(t *testing.T) {
|
|||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
runner := New(&fexec)
|
||||
runner := New(&fexec, ProtocolIpv4)
|
||||
err := runner.DeleteRule(TableNAT, ChainOutput, "abc", "123")
|
||||
if err != nil {
|
||||
t.Errorf("expected success, got %+v", err)
|
||||
|
@ -283,7 +302,7 @@ func TestDeleteRuleErrorChecking(t *testing.T) {
|
|||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
runner := New(&fexec)
|
||||
runner := New(&fexec, ProtocolIpv4)
|
||||
err := runner.DeleteRule(TableNAT, ChainOutput, "abc", "123")
|
||||
if err == nil {
|
||||
t.Errorf("expected failure")
|
||||
|
@ -309,7 +328,7 @@ func TestDeleteRuleErrorCreating(t *testing.T) {
|
|||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
runner := New(&fexec)
|
||||
runner := New(&fexec, ProtocolIpv4)
|
||||
err := runner.DeleteRule(TableNAT, ChainOutput, "abc", "123")
|
||||
if err == nil {
|
||||
t.Errorf("expected failure")
|
||||
|
|
Loading…
Reference in New Issue