Change:
On some systems, iptables-save outputs the following warning to stderr: Note that the error message includes a newline. Because kube-proxy captures both stdout and stderr when calling , the newline might cause rules to be garbled. For example, the output might contain the following line: The parser treats this as a chain line, and panics, as predicted in
/sig network
FYI
/triage unresolved Comment when the issue is assessed and confirmed. I am a bot run by vllry. ‍
/assign
Just FYI here's another example of garbled output:
Anyway, fix is in Please review.
/assign
/remove-triage unresolved

Discussion:
args := []string{"-t", string(table)} klog.V(4).Infof("running %s %v", iptablesSaveCmd, args) cmd := runner.exec.Command(iptablesSaveCmd, args...) <del> // Since CombinedOutput() doesn't support redirecting it to a buffer, // we need to workaround it by redirecting stdout and stderr to buffer // and explicitly calling Run() [CombinedOutput() underneath itself // creates a new buffer, redirects stdout and stderr to it and also // calls Run()]. </del> cmd.SetStdout(buffer) <del> cmd.SetStderr(buffer) return cmd.Run() </del> <ins> stderrBuffer := bytes.NewBuffer(nil) cmd.SetStderr(stderrBuffer) err := cmd.Run() if err != nil { stderrBuffer.WriteTo(buffer) // ignore error, since we need to return the original error } return err </ins> } // Restore is part of Interface.

COMMIT # Completed on Thu Jan 19 11:38:09 2017`, iptablesSaveCmd+version) <ins> stderrOutput := "#STDERR OUTPUT" // SaveInto() should should NOT capture stderr into the buffer </ins> fcmd := fakeexec.FakeCmd{ CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{ // iptables version check

func() ([]byte, error) { return []byte(iptablesRestoreCmd + version), nil }, }, RunScript: []fakeexec.FakeRunAction{ <del> func() ([]byte, []byte, error) { return []byte(output), nil, nil }, func() ([]byte, []byte, error) { return nil, nil, &fakeexec.FakeExitError{Status: 1} }, </del> <ins> func() ([]byte, []byte, error) { return []byte(output), []byte(stderrOutput), nil }, func() ([]byte, []byte, error) { return nil, []byte(stderrOutput), &fakeexec.FakeExitError{Status: 1} }, </ins> }, } fexec := fakeexec.FakeExec{

t.Fatalf("%s: Expected success, got %v", protoStr, err) } <del> if string(buffer.Bytes()[:len(output)]) != output { t.Errorf("%s: Expected output '%s', got '%v'", protoStr, output, buffer.Bytes()) </del> <ins> if string(buffer.Bytes()) != output { t.Errorf("%s: Expected output '%s', got '%v'", protoStr, output, string(buffer.Bytes())) </ins> } if fcmd.CombinedOutputCalls != 2 {

if err == nil { t.Errorf("%s: Expected failure", protoStr) } <ins> if string(buffer.Bytes()) != stderrOutput { t.Errorf("%s: Expected output '%s', got '%v'", protoStr, stderrOutput, string(buffer.Bytes())) } </ins> } func TestSaveIntoIPv4(t *testing.T) {

} else if line[0] == ':' && len(line) > 1 { // We assume that the <line> contains space - chain lines have 3 fields, // space delimited. If there is no space, this line will panic. <del> chain := Chain(line[1:bytes.Index(line, spaceBytes)]) </del> <ins> spaceIndex := bytes.Index(line, spaceBytes) if spaceIndex == -1 { panic(fmt.Sprintf("Unexpected chain line in iptables-save output: %v", string(line))) } chain := Chain(line[1:spaceIndex]) </ins> chainsMap[chain] = line } }