diff --git a/cmd/commands.go b/cmd/commands.go index 3daca6ab..e58c9539 100644 --- a/cmd/commands.go +++ b/cmd/commands.go @@ -55,7 +55,7 @@ const ( explainHelp = "flag to explain connectivity output with rules explanations per allowed/denied connections (default false)" synthesisDumpDirHelp = "apply synthesis; specify directory path to store k8s synthesis results" synthesizeAdminPoliciesHelp = "include admin network policies in policy synthesis (default false)" - outputFormatHelp = "output format; must be one of [txt, dot, json, svg]" + outputFormatHelp = "output format; must be one of " outputFilterFlagHelp = "filter the analysis results by vm names, can specify more than one (example: \"vm1,vm2\")" quietHelp = "flag to run quietly, report only severe errors and result (default false)" verboseHelp = "flag to run with more informative messages printed to log (default false)" @@ -74,7 +74,7 @@ type inArgs struct { skipAnalysis bool anonymise bool outputFile string - outputFormat string + outputFormat outFormat quiet bool verbose bool explain bool @@ -82,8 +82,12 @@ type inArgs struct { color bool } +func newInArgs() *inArgs { + return &inArgs{outputFormat: outFormatText} // init with default val for outputFormat +} + func newRootCommand() *cobra.Command { - args := &inArgs{} + args := newInArgs() rootCmd := &cobra.Command{ Use: "nsxanalyzer", Short: `nsxanalyzer is a CLI for collecting NSX resources, analysis of permitted connectivity between VMs, @@ -117,8 +121,7 @@ and generation of k8s network policies. It uses REST API calls from NSX manager. rootCmd.PersistentFlags().StringVar(&args.synthesisDumpDir, synthesisDumpDirFlag, "", synthesisDumpDirHelp) rootCmd.PersistentFlags().BoolVar(&args.synthesizeAdmin, synthesizeAdminPoliciesFlag, false, synthesizeAdminPoliciesHelp) rootCmd.PersistentFlags().StringVarP(&args.outputFile, outputFileFlag, outputFileShortFlag, "", outputFileHelp) - // todo - check if the format is valid - rootCmd.PersistentFlags().StringVarP(&args.outputFormat, outputFormatFlag, outputFormantShortFlag, common.TextFormat, outputFormatHelp) + rootCmd.PersistentFlags().VarP(&args.outputFormat, outputFormatFlag, outputFormantShortFlag, outputFormatHelp+allFormatsStr) rootCmd.PersistentFlags().BoolVarP(&args.quiet, quietFlag, "q", false, quietHelp) rootCmd.PersistentFlags().BoolVarP(&args.verbose, verboseFlag, "v", false, verboseHelp) rootCmd.PersistentFlags().BoolVarP(&args.explain, explainFlag, "e", false, explainHelp) @@ -187,7 +190,7 @@ func runCommand(args *inArgs) error { } } if args.topologyDumpFile != "" { - topology, err := resources.OutputTopologyGraph(args.topologyDumpFile, args.outputFormat) + topology, err := resources.OutputTopologyGraph(args.topologyDumpFile, args.outputFormat.String()) if err != nil { return err } @@ -195,7 +198,7 @@ func runCommand(args *inArgs) error { } if !args.skipAnalysis { params := common.OutputParameters{ - Format: args.outputFormat, + Format: args.outputFormat.String(), FileName: args.outputFile, VMs: args.outputFilter, Explain: args.explain, diff --git a/cmd/enum_flags.go b/cmd/enum_flags.go new file mode 100644 index 00000000..b5ef4891 --- /dev/null +++ b/cmd/enum_flags.go @@ -0,0 +1,40 @@ +package main + +import ( + "fmt" + + "github.com/np-guard/vmware-analyzer/pkg/common" +) + +type outFormat string + +var ( + outFormatText outFormat = common.TextFormat + outFormatDot outFormat = common.DotFormat + outFormatSvg outFormat = common.SvgFormat + outFormatJSON outFormat = common.JSONFormat +) + +var allFormats = []*outFormat{&outFormatText, &outFormatDot, &outFormatSvg, &outFormatJSON} +var allFormatsStr = common.JoinStringifiedSlice(allFormats, common.CommaSeparator) + +// String is used both by fmt.Print and by Cobra in help text +func (e *outFormat) String() string { + return string(*e) +} + +// Set must have pointer receiver so it doesn't change the value of a copy +func (e *outFormat) Set(v string) error { + switch v { + case common.TextFormat, common.DotFormat, common.JSONFormat, common.SvgFormat: + *e = outFormat(v) + return nil + default: + return fmt.Errorf("must be one of %s", allFormatsStr) + } +} + +// Type is only used in help text +func (e *outFormat) Type() string { + return "string" +} diff --git a/cmd/main_test.go b/cmd/main_test.go index 047af6e8..63e56606 100644 --- a/cmd/main_test.go +++ b/cmd/main_test.go @@ -61,6 +61,11 @@ const ( ) var staticTests = []*cliTest{ + { + name: "unsupported_format_check", + args: "-r ../pkg/collector/data/json/Example1.json -v -o svg -o ex1.svg ", + expectedErr: []string{"invalid argument"}, + }, { // version name: "version", diff --git a/pkg/model/connectivity/output.go b/pkg/model/connectivity/output.go index 4149135f..68e90514 100644 --- a/pkg/model/connectivity/output.go +++ b/pkg/model/connectivity/output.go @@ -1,6 +1,10 @@ package connectivity -import "github.com/np-guard/vmware-analyzer/pkg/common" +import ( + "fmt" + + "github.com/np-guard/vmware-analyzer/pkg/common" +) func (c ConnMap) GenTextualConnectivityOutput() (res string, err error) { return c.GenConnectivityOutput(common.OutputParameters{Format: common.TextFormat}) @@ -16,6 +20,8 @@ func (c ConnMap) GenConnectivityOutput(params common.OutputParameters) (res stri g = common.NewEdgesGraph(common.AnalyzedConnectivityHeader, []string{"Source", "Destination", "Permitted connections"}, params.Color) case common.DotFormat, common.SvgFormat: g = common.NewDotGraph(false) + default: + return "", fmt.Errorf("unsupported format %s", params.Format) } for _, e := range filteredConn.toSlice() { if !e.DetailedConn.Conn.IsEmpty() {