Skip to content

Commit 0a3a75f

Browse files
committed
Include nftables information in Agent supportbundle
Signed-off-by: molegit9 <[email protected]>
1 parent 3c81b27 commit 0a3a75f

File tree

2 files changed

+198
-0
lines changed

2 files changed

+198
-0
lines changed

pkg/support/dump_others.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,17 @@
1818
package support
1919

2020
import (
21+
"bytes"
2122
"fmt"
2223
"path"
2324
"path/filepath"
2425
"strings"
2526

27+
"k8s.io/klog/v2"
28+
testingexec "k8s.io/utils/exec/testing"
29+
2630
"antrea.io/antrea/pkg/agent/util/iptables"
31+
nftclient "antrea.io/antrea/pkg/agent/util/nftables"
2732
"antrea.io/antrea/pkg/util/logdir"
2833
)
2934

@@ -41,6 +46,9 @@ func (d *agentDumper) DumpHostNetworkInfo(basedir string) error {
4146
if err := d.dumpIPTables(basedir); err != nil {
4247
return err
4348
}
49+
if err := d.dumpNFTables(basedir); err != nil {
50+
return err
51+
}
4452
if err := d.dumpIPToolInfo(basedir); err != nil {
4553
return err
4654
}
@@ -59,6 +67,50 @@ func (d *agentDumper) dumpIPTables(basedir string) error {
5967
return writeFile(d.fs, filepath.Join(basedir, "iptables"), "iptables", data)
6068
}
6169

70+
func (d *agentDumper) dumpNFTables(basedir string) error {
71+
if _, isFake := d.executor.(*testingexec.FakeExec); !isFake {
72+
if _, err := nftclient.New(d.v4Enabled, d.v6Enabled); err != nil {
73+
klog.ErrorS(err, "Skipping nftables dump because it is not supported on this Node")
74+
return nil
75+
}
76+
}
77+
78+
var data bytes.Buffer
79+
80+
if d.v4Enabled {
81+
output, err := d.executor.Command("nft", "list", "table", "ip", "antrea").CombinedOutput()
82+
if err != nil {
83+
return fmt.Errorf("failed to dump nftables table 'ip antrea': %w", err)
84+
}
85+
if len(output) > 0 {
86+
data.Write(output)
87+
data.WriteString("\n")
88+
}
89+
}
90+
91+
if d.v6Enabled {
92+
output, err := d.executor.Command("nft", "list", "table", "ip6", "antrea").CombinedOutput()
93+
if err != nil {
94+
return fmt.Errorf("failed to dump nftables table 'ip6 antrea': %w", err)
95+
}
96+
if len(output) > 0 {
97+
data.Write(output)
98+
data.WriteString("\n")
99+
}
100+
}
101+
102+
if data.Len() == 0 {
103+
return nil
104+
}
105+
106+
fileName := "nftables"
107+
if err := writeFile(d.fs, filepath.Join(basedir, fileName), fileName, data.Bytes()); err != nil {
108+
return fmt.Errorf("failed to write nftables file: %w", err)
109+
}
110+
111+
return nil
112+
}
113+
62114
func (d *agentDumper) dumpIPToolInfo(basedir string) error {
63115
dump := func(name string) error {
64116
output, err := d.executor.Command("ip", name).CombinedOutput()

pkg/support/dump_others_test.go

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package support
1919

2020
import (
21+
"fmt"
2122
"os"
2223
"path/filepath"
2324
"testing"
@@ -27,6 +28,8 @@ import (
2728
"github.com/spf13/afero"
2829
"github.com/stretchr/testify/assert"
2930
"github.com/stretchr/testify/require"
31+
"k8s.io/utils/exec"
32+
testingexec "k8s.io/utils/exec/testing"
3033
)
3134

3235
func TestDumpLog(t *testing.T) {
@@ -49,3 +52,146 @@ func TestDumpLog(t *testing.T) {
4952
require.NoError(t, err)
5053
assert.True(t, ok)
5154
}
55+
56+
func TestDumpNFTables(t *testing.T) {
57+
const nftV4Output = "table ip antrea { chain antrea-chain { type filter hook input priority 0; } }"
58+
const nftV6Output = "table ip6 antrea { chain antrea-chain6 { type filter hook input priority 0; } }"
59+
60+
v4ErrorAction := func() ([]byte, []byte, error) {
61+
return nil, nil, fmt.Errorf("v4 error")
62+
}
63+
v4SuccessAction := func() ([]byte, []byte, error) {
64+
return []byte(nftV4Output), nil, nil
65+
}
66+
v6SuccessAction := func() ([]byte, []byte, error) {
67+
return []byte(nftV6Output), nil, nil
68+
}
69+
emptySuccessAction := func() ([]byte, []byte, error) {
70+
return []byte(""), nil, nil
71+
}
72+
73+
tests := []struct {
74+
name string
75+
v4Enabled bool
76+
v6Enabled bool
77+
commandActions []testingexec.FakeCommandAction
78+
expectedContent string
79+
expectFile bool
80+
expectErr bool
81+
}{
82+
{
83+
name: "v4 enabled only",
84+
v4Enabled: true,
85+
v6Enabled: false,
86+
commandActions: []testingexec.FakeCommandAction{
87+
func(cmd string, args ...string) exec.Cmd {
88+
return &testingexec.FakeCmd{
89+
CombinedOutputScript: []testingexec.FakeAction{v4SuccessAction},
90+
}
91+
},
92+
},
93+
expectedContent: nftV4Output + "\n",
94+
expectFile: true,
95+
},
96+
{
97+
name: "v6 enabled only",
98+
v4Enabled: false,
99+
v6Enabled: true,
100+
commandActions: []testingexec.FakeCommandAction{
101+
func(cmd string, args ...string) exec.Cmd {
102+
return &testingexec.FakeCmd{
103+
CombinedOutputScript: []testingexec.FakeAction{v6SuccessAction},
104+
}
105+
},
106+
},
107+
expectedContent: nftV6Output + "\n",
108+
expectFile: true,
109+
},
110+
{
111+
name: "v4 and v6 enabled",
112+
v4Enabled: true,
113+
v6Enabled: true,
114+
commandActions: []testingexec.FakeCommandAction{
115+
func(cmd string, args ...string) exec.Cmd {
116+
return &testingexec.FakeCmd{
117+
CombinedOutputScript: []testingexec.FakeAction{v4SuccessAction},
118+
}
119+
},
120+
func(cmd string, args ...string) exec.Cmd {
121+
return &testingexec.FakeCmd{
122+
CombinedOutputScript: []testingexec.FakeAction{v6SuccessAction},
123+
}
124+
},
125+
},
126+
expectedContent: nftV4Output + "\n" + nftV6Output + "\n",
127+
expectFile: true,
128+
},
129+
{
130+
name: "v4 command error",
131+
v4Enabled: true,
132+
v6Enabled: true,
133+
commandActions: []testingexec.FakeCommandAction{
134+
func(cmd string, args ...string) exec.Cmd {
135+
return &testingexec.FakeCmd{
136+
CombinedOutputScript: []testingexec.FakeAction{v4ErrorAction},
137+
}
138+
},
139+
},
140+
expectFile: false,
141+
expectErr: true,
142+
},
143+
{
144+
name: "no rules found (empty output)",
145+
v4Enabled: true,
146+
v6Enabled: true,
147+
commandActions: []testingexec.FakeCommandAction{
148+
func(cmd string, args ...string) exec.Cmd {
149+
return &testingexec.FakeCmd{CombinedOutputScript: []testingexec.FakeAction{emptySuccessAction}}
150+
},
151+
func(cmd string, args ...string) exec.Cmd {
152+
return &testingexec.FakeCmd{CombinedOutputScript: []testingexec.FakeAction{emptySuccessAction}}
153+
},
154+
},
155+
expectFile: false,
156+
expectErr: false,
157+
},
158+
}
159+
160+
for _, tc := range tests {
161+
t.Run(tc.name, func(t *testing.T) {
162+
fs := afero.NewMemMapFs()
163+
fs.MkdirAll(baseDir, os.ModePerm)
164+
165+
fakeExecutor := &testingexec.FakeExec{}
166+
fakeExecutor.CommandScript = tc.commandActions
167+
168+
dumper := &agentDumper{
169+
fs: fs,
170+
executor: fakeExecutor,
171+
v4Enabled: tc.v4Enabled,
172+
v6Enabled: tc.v6Enabled,
173+
}
174+
175+
err := dumper.dumpNFTables(baseDir)
176+
177+
if tc.expectErr {
178+
require.Error(t, err)
179+
return
180+
}
181+
182+
require.NoError(t, err)
183+
184+
filePath := filepath.Join(baseDir, "nftables")
185+
186+
ok, err := afero.Exists(fs, filePath)
187+
require.NoError(t, err)
188+
assert.Equal(t, tc.expectFile, ok, "Expected nftables file existence to be %t", tc.expectFile)
189+
190+
if tc.expectFile {
191+
content, err := afero.ReadFile(fs, filePath)
192+
require.NoError(t, err)
193+
assert.Equal(t, tc.expectedContent, string(content), "File content does not match")
194+
}
195+
})
196+
}
197+
}

0 commit comments

Comments
 (0)