Skip to content

Commit

Permalink
Add a flag for antctl to print OVS table names only (#5895)
Browse files Browse the repository at this point in the history
The flag is `--table-names-only`.
Usage: `antctl get ovsflows --table-names-only`.

Signed-off-by: Lan Luo <luola@vmware.com>
  • Loading branch information
luolanzone authored Feb 21, 2024
1 parent 968649c commit e3f07df
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 29 deletions.
36 changes: 31 additions & 5 deletions pkg/agent/apiserver/handlers/ovsflows/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package ovsflows
import (
"encoding/json"
"net/http"
"sort"
"strconv"
"strings"

Expand All @@ -33,6 +34,7 @@ var (
// Use function variables for tests.
getFlowTableName = openflow.GetFlowTableName
getFlowTableID = openflow.GetFlowTableID
getFlowTableList = openflow.GetTableList
)

// Response is the response struct of ovsflows command.
Expand Down Expand Up @@ -183,6 +185,19 @@ func getNetworkPolicyFlows(aq agentquerier.AgentQuerier, npName, namespace strin
return dumpMatchedFlows(aq, flowKeys)
}

func getTableNames(aq agentquerier.AgentQuerier) []Response {
resps := []Response{}
names := []string{}
for _, t := range getFlowTableList() {
names = append(names, t.GetName())
}
sort.Strings(names)
for _, name := range names {
resps = append(resps, Response{name})
}
return resps
}

// HandleFunc returns the function which can handle API requests to "/ovsflows".
func HandleFunc(aq agentquerier.AgentQuerier) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
Expand All @@ -194,6 +209,20 @@ func HandleFunc(aq agentquerier.AgentQuerier) http.HandlerFunc {
namespace := r.URL.Query().Get("namespace")
table := r.URL.Query().Get("table")
groups := r.URL.Query().Get("groups")
tableNamesOnly := r.URL.Query().Has("table-names-only")

encodeResp := func() {
err = json.NewEncoder(w).Encode(resps)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
}

if tableNamesOnly {
resps = getTableNames(aq)
encodeResp()
return
}

if (pod != "" || service != "" || networkPolicy != "") && namespace == "" {
http.Error(w, "namespace must be provided", http.StatusBadRequest)
Expand Down Expand Up @@ -240,17 +269,14 @@ func HandleFunc(aq agentquerier.AgentQuerier) http.HandlerFunc {
return
}

err = json.NewEncoder(w).Encode(resps)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
encodeResp()
}
}

var _ common.TableOutput = new(Response)

func (r Response) GetTableHeader() []string {
return []string{"FLOW"}
return []string{""}
}

func (r Response) GetTableRow(maxColumnLength int) []string {
Expand Down
20 changes: 20 additions & 0 deletions pkg/agent/apiserver/handlers/ovsflows/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,19 @@ func TestTableFlows(t *testing.T) {

}

func TestTableNamesOnly(t *testing.T) {
ctrl := gomock.NewController(t)
getFlowTableList = mockGetTableList
tc := testCase{
test: "Get table names only",
query: "?table-names-only",
expectedStatus: http.StatusOK,
resps: []Response{{"table0"}, {"table1"}},
}
q := aqtest.NewMockAgentQuerier(ctrl)
runHTTPTest(t, &tc, q)
}

func mockGetFlowTableName(id uint8) string {
if id == 80 {
return "IngressRule"
Expand All @@ -254,6 +267,13 @@ func mockGetFlowTableID(tableName string) uint8 {
return binding.TableIDAll
}

func mockGetTableList() []binding.Table {
return []binding.Table{
binding.NewOFTable(0, "table0", 0, 0, 0),
binding.NewOFTable(0, "table1", 0, 0, 0),
}
}

func TestGroups(t *testing.T) {
ctrl := gomock.NewController(t)
testcases := []struct {
Expand Down
2 changes: 1 addition & 1 deletion pkg/agent/openflow/pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ func GetFlowTableID(tableName string) uint8 {
func GetTableList() []binding.Table {
tables := make([]binding.Table, 0)
for _, obj := range tableCache.List() {
t := obj.(binding.Table)
t := obj.(*Table).ofTable
tables = append(tables, t)
}
return tables
Expand Down
21 changes: 8 additions & 13 deletions pkg/antctl/antctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
package antctl

import (
"fmt"
"reflect"

"antrea.io/antrea/pkg/agent/apiserver/handlers/agentinfo"
Expand All @@ -24,7 +23,6 @@ import (
"antrea.io/antrea/pkg/agent/apiserver/handlers/ovsflows"
"antrea.io/antrea/pkg/agent/apiserver/handlers/podinterface"
"antrea.io/antrea/pkg/agent/apiserver/handlers/serviceexternalip"
"antrea.io/antrea/pkg/agent/openflow"
fallbackversion "antrea.io/antrea/pkg/antctl/fallback/version"
"antrea.io/antrea/pkg/antctl/raw/featuregates"
"antrea.io/antrea/pkg/antctl/raw/multicluster"
Expand Down Expand Up @@ -370,6 +368,8 @@ $ antctl get podmulticaststats pod -n namespace`,
long: "Dump all the OVS flows or the flows installed for the specified entity.",
example: ` Dump all OVS flows
$ antctl get ovsflows
Dump OVS table names only
$ antctl get ovsflows --table-names-only
Dump OVS flows of a local Pod
$ antctl get ovsflows -p pod1 -n ns1
Dump OVS flows of a Service
Expand All @@ -381,9 +381,7 @@ $ antctl get podmulticaststats pod -n namespace`,
Dump OVS groups
$ antctl get ovsflows -G 10,20
Dump all OVS groups
$ antctl get ovsflows -G all
Antrea OVS Flow Tables:` + generateFlowTableHelpMsg(),
$ antctl get ovsflows -G all`,
agentEndpoint: &endpoint{
nonResourceEndpoint: &nonResourceEndpoint{
path: "/ovsflows",
Expand Down Expand Up @@ -413,6 +411,11 @@ $ antctl get podmulticaststats pod -n namespace`,
usage: "Comma separated Antrea OVS flow table names or numbers",
shorthand: "T",
},
{
name: "table-names-only",
usage: "Print all Antrea OVS flow table names only, and nothing else",
isBool: true,
},
{
name: "groups",
usage: "Comma separated OVS group IDs. Use 'all' to dump all groups",
Expand Down Expand Up @@ -689,11 +692,3 @@ $ antctl get podmulticaststats pod -n namespace`,
},
codec: scheme.Codecs,
}

func generateFlowTableHelpMsg() string {
msg := ""
for _, t := range openflow.GetTableList() {
msg += fmt.Sprintf("\n %d\t%s", uint32(t.GetID()), t.GetName())
}
return msg
}
38 changes: 28 additions & 10 deletions pkg/antctl/command_definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ type flagInfo struct {
supportedValues []string
arg bool
usage string
isBool bool
}

// rawCommand defines a full function cobra.Command which lets developers
Expand Down Expand Up @@ -562,13 +563,25 @@ func (cd *commandDefinition) collectFlags(cmd *cobra.Command, args []string) (ma
argMap[f.name] = args[0]
}
} else {
vs, err := cmd.Flags().GetString(f.name)
if err == nil && len(vs) != 0 {
if f.supportedValues != nil && !cd.validateFlagValue(vs, f.supportedValues) {
return nil, fmt.Errorf("unsupported value %s for flag %s", vs, f.name)
if f.isBool {
vs, err := cmd.Flags().GetBool(f.name)
if err != nil {
return nil, fmt.Errorf("error accessing flag %s for command %s: %v", f.name, cmd.Name(), err)
}
if vs {
argMap[f.name] = ""
}
} else {
vs, err := cmd.Flags().GetString(f.name)
if err != nil {
return nil, fmt.Errorf("error accessing flag %s for command %s: %v", f.name, cmd.Name(), err)
}
if err == nil && len(vs) != 0 {
if f.supportedValues != nil && !cd.validateFlagValue(vs, f.supportedValues) {
return nil, fmt.Errorf("unsupported value %s for flag %s", vs, f.name)
}
argMap[f.name] = vs
}
argMap[f.name] = vs
continue
}
}
}
Expand Down Expand Up @@ -639,18 +652,23 @@ func (cd *commandDefinition) newCommandRunE(c AntctlClient, out io.Writer) func(

// applyFlagsToCommand sets up args and flags for the command.
func (cd *commandDefinition) applyFlagsToCommand(cmd *cobra.Command) {
var hasFlag bool
var hasArg bool
for _, flag := range cd.getEndpoint().flags() {
if flag.arg {
cmd.Args = cobra.MaximumNArgs(1)
cmd.Use += fmt.Sprintf(" [%s]", flag.name)
cmd.Long += fmt.Sprintf("\n\nArgs:\n %s\t%s", flag.name, flag.usage)
hasFlag = true
hasArg = true
} else {
cmd.Flags().StringP(flag.name, flag.shorthand, flag.defaultValue, flag.usage)
if flag.isBool {
// When the flag is a boolean, the default value will always be false.
cmd.Flags().BoolP(flag.name, flag.shorthand, false, flag.usage)
} else {
cmd.Flags().StringP(flag.name, flag.shorthand, flag.defaultValue, flag.usage)
}
}
}
if !hasFlag {
if !hasArg {
cmd.Args = cobra.NoArgs
}
if cd.commandGroup == get {
Expand Down
5 changes: 5 additions & 0 deletions pkg/antctl/command_definition_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1055,6 +1055,11 @@ func TestCollectFlags(t *testing.T) {
usage: "Comma separated Antrea OVS flow table names or numbers",
shorthand: "T",
},
{
name: "table-names-only",
usage: "Print all Antrea OVS flow table names only, and nothing else",
isBool: true,
},
{
name: "groups",
defaultValue: "Groups",
Expand Down

0 comments on commit e3f07df

Please sign in to comment.