Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

accept a description of a connection in the cli and translate it to co… #319

Merged
merged 12 commits into from
Jan 15, 2024
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 {
ShiriMoran marked this conversation as resolved.
Show resolved Hide resolved
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
}
ShiriMoran marked this conversation as resolved.
Show resolved Hide resolved

// 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)
}

olasaadi99 marked this conversation as resolved.
Show resolved Hide resolved
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