Skip to content

Commit

Permalink
accept a description of a connection in the cli and translate it to c…
Browse files Browse the repository at this point in the history
…o… (#319)

* add explainMode analysis-type which accepts a description of a connection in the cli and translate it to common.ConnectionSet
---------
Signed-off-by: Ola Saadi <[email protected]>
  • Loading branch information
olasaadi99 authored Jan 15, 2024
1 parent ff6e34c commit f50617b
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 0 deletions.
21 changes: 21 additions & 0 deletions cmd/analyzer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"log"
"os"

"github.com/np-guard/vpc-network-config-analyzer/pkg/common"
"github.com/np-guard/vpc-network-config-analyzer/pkg/ibmvpc"
"github.com/np-guard/vpc-network-config-analyzer/pkg/version"
"github.com/np-guard/vpc-network-config-analyzer/pkg/vpcmodel"
Expand Down Expand Up @@ -48,6 +49,8 @@ func analysisTypeToUseCase(inArgs *InArgs) vpcmodel.OutputUseCase {
return vpcmodel.SubnetsDiff
case allEndpointsDiff:
return vpcmodel.EndpointsDiff
case explainMode:
return vpcmodel.Explain
}
return vpcmodel.AllEndpoints
}
Expand Down Expand Up @@ -83,6 +86,19 @@ func vpcConfigsFromFile(fileName string, inArgs *InArgs) (map[string]*vpcmodel.V
return vpcConfigs, nil
}

func translateCDtoConnectionSet(inArgs *InArgs) *common.ConnectionSet {
connection := common.NewConnectionSet(false)
if common.ProtocolStr(*inArgs.QProtocol) == common.ProtocolICMP {
connection.AddICMPConnection(common.MinICMPtype, common.MaxICMPtype,
common.MinICMPcode, common.MaxICMPcode)
} else {
connection.AddTCPorUDPConn(common.ProtocolStr(*inArgs.QProtocol), *inArgs.QSrcMinPort, *inArgs.QSrcMaxPort,
*inArgs.QDstMinPort, *inArgs.QDstMaxPort)
}

return connection
}

// The actual main function
// Takes command-line flags and returns an error rather than exiting, so it can be more easily used in testing
func _main(cmdlineArgs []string) error {
Expand Down Expand Up @@ -123,6 +139,11 @@ func _main(cmdlineArgs []string) error {
return err2
}
fmt.Println(vpcAnalysisOutput)

if *inArgs.AnalysisType == explainMode {
_ = translateCDtoConnectionSet(inArgs)
}

return nil
}

Expand Down
103 changes: 103 additions & 0 deletions cmd/analyzer/parse_args.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"fmt"
"slices"
"strings"

"github.com/np-guard/vpc-network-config-analyzer/pkg/common"
)

// InArgs contains the input arguments for the analyzer
Expand All @@ -18,6 +20,11 @@ type InArgs struct {
VPC *string
Debug *bool
Version *bool
QProtocol *string
QSrcMinPort *int64
QSrcMaxPort *int64
QDstMinPort *int64
QDstMaxPort *int64
}

// flagHasValue indicates for each input arg if it is expected to have a value in the cli or not
Expand All @@ -31,6 +38,11 @@ var flagHasValue = map[string]bool{
VPC: true,
Debug: false,
Version: false,
QProtocol: true,
QSrcMinPort: true,
QSrcMaxPort: true,
QDstMinPort: true,
QDstMaxPort: true,
}

const (
Expand All @@ -44,6 +56,11 @@ const (
VPC = "vpc"
Debug = "debug"
Version = "version"
QProtocol = "q-protocol"
QSrcMinPort = "q-src-min-port"
QSrcMaxPort = "q-src-max-port"
QDstMinPort = "q-dst-min-port"
QDstMaxPort = "q-dst-max-port"

// output formats supported
JSONFormat = "json"
Expand All @@ -59,6 +76,7 @@ const (
singleSubnet = "single_subnet" // single subnet connectivity analysis
allEndpointsDiff = "diff_all_endpoints" // semantic diff of allEndpoints analysis between two configurations
allSubnetsDiff = "diff_all_subnets" // semantic diff of allSubnets analysis between two configurations
explainMode = "explain" // explain specified connectivity, given src,dst and connection

// separator
separator = ", "
Expand All @@ -80,6 +98,7 @@ var supportedAnalysisTypesMap = map[string][]string{
singleSubnet: {TEXTFormat},
allEndpointsDiff: {TEXTFormat, MDFormat},
allSubnetsDiff: {TEXTFormat, MDFormat},
explainMode: {TEXTFormat},
}

// supportedOutputFormatsList is an ordered list of supported output formats (usage details presented in this order)
Expand All @@ -99,6 +118,7 @@ var supportedAnalysisTypesList = []string{
singleSubnet,
allEndpointsDiff,
allSubnetsDiff,
explainMode,
}

func getSupportedAnalysisTypesMapString() string {
Expand Down Expand Up @@ -160,6 +180,11 @@ func ParseInArgs(cmdlineArgs []string) (*InArgs, error) {
args.VPC = flagset.String(VPC, "", "CRN of the VPC to analyze")
args.Debug = flagset.Bool(Debug, false, "Run in debug mode")
args.Version = flagset.Bool(Version, false, "Prints the release version number")
args.QProtocol = flagset.String(QProtocol, "", "Protocol for connection description")
args.QSrcMinPort = flagset.Int64(QSrcMinPort, common.MinPort, "SrcMinPort for connection description")
args.QSrcMaxPort = flagset.Int64(QSrcMaxPort, common.MaxPort, "SrcMaxPort for connection description")
args.QDstMinPort = flagset.Int64(QDstMinPort, common.MinPort, "DstMinPort for connection description")
args.QDstMaxPort = flagset.Int64(QDstMaxPort, common.MaxPort, "DstMaxPort for connection description")

// calling parseCmdLine prior to flagset.Parse to ensure that excessive and unsupported arguments are handled
// for example, flagset.Parse() ignores input args missing the `-`
Expand All @@ -180,9 +205,87 @@ func ParseInArgs(cmdlineArgs []string) (*InArgs, error) {
if err != nil {
return nil, err
}
err = invalidArgsExplainMode(&args, flagset)
if err != nil {
return nil, err
}

return &args, nil
}

func wasFlagSpecified(name string, flagset *flag.FlagSet) bool {
found := false
flagset.Visit(func(f *flag.Flag) {
if f.Name == name {
found = true
}
})
return found
}

func wereExplainParamsSpecified(flagset *flag.FlagSet) bool {
if wasFlagSpecified(QProtocol, flagset) || wasFlagSpecified(QSrcMinPort, flagset) || wasFlagSpecified(QSrcMaxPort, flagset) ||
wasFlagSpecified(QDstMinPort, flagset) || wasFlagSpecified(QDstMaxPort, flagset) {
return true
}

return false
}

func PortInRange(port int64) bool {
if port > common.MaxPort || port < common.MinPort {
return false
}

return true
}

func minMaxValidity(minPort, maxPort int64, minPortName, maxPortName string) error {
if minPort > maxPort {
return fmt.Errorf("%s %d must not be larger than %s %d", minPortName, minPort, maxPortName, maxPort)
}

return nil
}

func validRangeConnectionExplainMode(args *InArgs) error {
err := minMaxValidity(*args.QSrcMinPort, *args.QSrcMaxPort, QSrcMinPort, QSrcMaxPort)
if err != nil {
return err
}
err = minMaxValidity(*args.QDstMinPort, *args.QDstMaxPort, QDstMinPort, QDstMaxPort)
if err != nil {
return err
}

if !PortInRange(*args.QSrcMinPort) || !PortInRange(*args.QSrcMaxPort) ||
!PortInRange(*args.QDstMinPort) || !PortInRange(*args.QDstMaxPort) {
return fmt.Errorf("%s, %s, %s and %s must be in ranges [%d, %d]",
QSrcMinPort, QSrcMaxPort, QDstMinPort, QDstMaxPort, common.MinPort, common.MaxPort)
}

return nil
}

func invalidArgsExplainMode(args *InArgs, flagset *flag.FlagSet) error {
if *args.AnalysisType != explainMode && wereExplainParamsSpecified(flagset) {
return fmt.Errorf("%s, %s, %s, %s and %s can be specified only when analysis-type is %s",
QProtocol, QSrcMinPort, QSrcMaxPort, QDstMinPort, QDstMaxPort, explainMode)
}

if *args.AnalysisType != explainMode {
return nil
}

protocol := strings.ToUpper(*args.QProtocol)
if protocol != string(common.ProtocolTCP) && protocol != string(common.ProtocolUDP) && protocol != string(common.ProtocolICMP) {
return fmt.Errorf("wrong connection description protocol '%s'; must be one of: 'TCP, UDP, ICMP'", protocol)
}
args.QProtocol = &protocol

return validRangeConnectionExplainMode(args)
}

func errorInErgs(args *InArgs, flagset *flag.FlagSet) error {
if !*args.Version && (args.InputConfigFile == nil || *args.InputConfigFile == "") {
flagset.PrintDefaults()
Expand Down
1 change: 1 addition & 0 deletions pkg/vpcmodel/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const (
AllSubnetsNoPGW // connectivity between subnets (consider nacl only)
SubnetsDiff // diff between subnets connectivity of two cfgs (consider nacl + pgw)
EndpointsDiff // diff between vsis connectivity of two cfgs
Explain // explain specified connectivity, given src,dst and connection
)

// OutputGenerator captures one vpc config1 with its connectivity analysis results, and implements
Expand Down

0 comments on commit f50617b

Please sign in to comment.