|
@@ -16,8 +16,10 @@
|
|
|
package network
|
|
|
|
|
|
import (
|
|
|
+ "fmt"
|
|
|
"net"
|
|
|
"reflect"
|
|
|
+ "strings"
|
|
|
"testing"
|
|
|
|
|
|
"github.com/coreos/flannel/pkg/ip"
|
|
@@ -32,7 +34,32 @@ func lease() *subnet.Lease {
|
|
|
}
|
|
|
|
|
|
type MockIPTables struct {
|
|
|
- rules []IPTablesRule
|
|
|
+ rules []IPTablesRule
|
|
|
+ t *testing.T
|
|
|
+ failures map[string]*MockIPTablesError
|
|
|
+}
|
|
|
+
|
|
|
+type MockIPTablesError struct {
|
|
|
+ notExist bool
|
|
|
+}
|
|
|
+
|
|
|
+func (mock *MockIPTablesError) IsNotExist() bool {
|
|
|
+ return mock.notExist
|
|
|
+}
|
|
|
+
|
|
|
+func (mock *MockIPTablesError) Error() string {
|
|
|
+ return fmt.Sprintf("IsNotExist: %v", !mock.notExist)
|
|
|
+}
|
|
|
+
|
|
|
+func (mock *MockIPTables) failDelete(table string, chain string, rulespec []string, notExist bool) {
|
|
|
+
|
|
|
+ if mock.failures == nil {
|
|
|
+ mock.failures = make(map[string]*MockIPTablesError)
|
|
|
+ }
|
|
|
+ key := table + chain + strings.Join(rulespec, "")
|
|
|
+ mock.failures[key] = &MockIPTablesError{
|
|
|
+ notExist: notExist,
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
func (mock *MockIPTables) ruleIndex(table string, chain string, rulespec []string) int {
|
|
@@ -46,6 +73,12 @@ func (mock *MockIPTables) ruleIndex(table string, chain string, rulespec []strin
|
|
|
|
|
|
func (mock *MockIPTables) Delete(table string, chain string, rulespec ...string) error {
|
|
|
var ruleIndex = mock.ruleIndex(table, chain, rulespec)
|
|
|
+ key := table + chain + strings.Join(rulespec, "")
|
|
|
+ reason := mock.failures[key]
|
|
|
+ if reason != nil {
|
|
|
+ return reason
|
|
|
+ }
|
|
|
+
|
|
|
if ruleIndex != -1 {
|
|
|
mock.rules = append(mock.rules[:ruleIndex], mock.rules[ruleIndex+1:]...)
|
|
|
}
|
|
@@ -69,7 +102,7 @@ func (mock *MockIPTables) AppendUnique(table string, chain string, rulespec ...s
|
|
|
}
|
|
|
|
|
|
func TestDeleteRules(t *testing.T) {
|
|
|
- ipt := &MockIPTables{}
|
|
|
+ ipt := &MockIPTables{t: t}
|
|
|
setupIPTables(ipt, MasqRules(ip.IP4Net{}, lease()))
|
|
|
if len(ipt.rules) != 4 {
|
|
|
t.Errorf("Should be 4 masqRules, there are actually %d: %#v", len(ipt.rules), ipt.rules)
|
|
@@ -80,16 +113,44 @@ func TestDeleteRules(t *testing.T) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+func TestEnsureRulesError(t *testing.T) {
|
|
|
+ // If an error prevents a rule from being deleted, ensureIPTables should leave the rules as is
|
|
|
+ // rather than potentially re-appending rules in an incorrect order
|
|
|
+ ipt_correct := &MockIPTables{t: t}
|
|
|
+ setupIPTables(ipt_correct, MasqRules(ip.IP4Net{}, lease()))
|
|
|
+ // setup a mock instance where we delete some masqRules and run `ensureIPTables`
|
|
|
+ ipt_recreate := &MockIPTables{t: t}
|
|
|
+ setupIPTables(ipt_recreate, MasqRules(ip.IP4Net{}, lease()))
|
|
|
+ ipt_recreate.rules = ipt_recreate.rules[0:2]
|
|
|
+
|
|
|
+ rule := ipt_recreate.rules[1]
|
|
|
+ ipt_recreate.failDelete(rule.table, rule.chain, rule.rulespec, false)
|
|
|
+ err := ensureIPTables(ipt_recreate, MasqRules(ip.IP4Net{}, lease()))
|
|
|
+ if err == nil {
|
|
|
+ t.Errorf("ensureIPTables should have failed but did not.")
|
|
|
+ }
|
|
|
+
|
|
|
+ if len(ipt_recreate.rules) == len(ipt_correct.rules) {
|
|
|
+ t.Errorf("ensureIPTables should not have completed.")
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
func TestEnsureRules(t *testing.T) {
|
|
|
// If any masqRules are missing, they should be all deleted and recreated in the correct order
|
|
|
- ipt_correct := &MockIPTables{}
|
|
|
+ ipt_correct := &MockIPTables{t: t}
|
|
|
setupIPTables(ipt_correct, MasqRules(ip.IP4Net{}, lease()))
|
|
|
// setup a mock instance where we delete some masqRules and run `ensureIPTables`
|
|
|
- ipt_recreate := &MockIPTables{}
|
|
|
+ ipt_recreate := &MockIPTables{t: t}
|
|
|
setupIPTables(ipt_recreate, MasqRules(ip.IP4Net{}, lease()))
|
|
|
ipt_recreate.rules = ipt_recreate.rules[0:2]
|
|
|
- ensureIPTables(ipt_recreate, MasqRules(ip.IP4Net{}, lease()))
|
|
|
+ // set up a normal error that iptables returns when deleting a rule that is already gone
|
|
|
+ deletedRule := ipt_correct.rules[3]
|
|
|
+ ipt_recreate.failDelete(deletedRule.table, deletedRule.chain, deletedRule.rulespec, true)
|
|
|
+ err := ensureIPTables(ipt_recreate, MasqRules(ip.IP4Net{}, lease()))
|
|
|
+ if err != nil {
|
|
|
+ t.Errorf("ensureIPTables should have completed without errors")
|
|
|
+ }
|
|
|
if !reflect.DeepEqual(ipt_recreate.rules, ipt_correct.rules) {
|
|
|
- t.Errorf("iptables masqRules after ensureIPTables are incorrected. Expected: %#v, Actual: %#v", ipt_recreate.rules, ipt_correct.rules)
|
|
|
+ t.Errorf("iptables masqRules after ensureIPTables are incorrect. Expected: %#v, Actual: %#v", ipt_recreate.rules, ipt_correct.rules)
|
|
|
}
|
|
|
}
|