diff --git a/cmd/subcmds/optimize.go b/cmd/subcmds/optimize.go index cf8ec17e..5bde4287 100644 --- a/cmd/subcmds/optimize.go +++ b/cmd/subcmds/optimize.go @@ -5,17 +5,39 @@ SPDX-License-Identifier: Apache-2.0 package subcmds -import "github.com/spf13/cobra" +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/np-guard/vpc-network-config-synthesis/pkg/ir" + "github.com/np-guard/vpc-network-config-synthesis/pkg/optimize" +) func NewOptimizeCommand(args *inArgs) *cobra.Command { cmd := &cobra.Command{ Use: "optimize", - Short: "Optimize is not supported yet", - Long: `Optimize is not supported yet`, + Short: "optimization of existing SG and nACLs", + Long: `optimization of existing SG and nACLs`, } - cmd.AddCommand(NewOptimizeACLCommand(args)) + // sub cmds cmd.AddCommand(NewOptimizeSGCommand(args)) + cmd.AddCommand(NewOptimizeACLCommand(args)) return cmd } + +func optimization(cmd *cobra.Command, args *inArgs, newOptimizer func(ir.Collection, string) optimize.Optimizer, isSG bool) error { + cmd.SilenceUsage = true // if we got this far, flags are syntactically correct, so no need to print usage + collection, err := parseCollection(args, isSG) + if err != nil { + return fmt.Errorf("could not parse config file %v: %w", args.configFile, err) + } + optimizer := newOptimizer(collection, args.firewallName) + optimizedCollection, err := optimizer.Optimize() + if err != nil { + return err + } + return writeOutput(args, optimizedCollection, collection.VpcNames(), false) +} diff --git a/cmd/subcmds/optimizeACL.go b/cmd/subcmds/optimizeACL.go index beb8e09b..c40d38a7 100644 --- a/cmd/subcmds/optimizeACL.go +++ b/cmd/subcmds/optimizeACL.go @@ -5,18 +5,27 @@ SPDX-License-Identifier: Apache-2.0 package subcmds -import "github.com/spf13/cobra" +import ( + "github.com/spf13/cobra" + + acloptimizer "github.com/np-guard/vpc-network-config-synthesis/pkg/optimize/acl" +) + +const aclNameFlag = "acl-name" func NewOptimizeACLCommand(args *inArgs) *cobra.Command { cmd := &cobra.Command{ Use: "acl", - Short: "OptimizeACL is not supported yet", - Long: `OptimizeACL is not supported yet`, + Short: "OptimizeACL attempts to reduce the number of nACL rules in an nACL without changing the semantic.", + Long: `OptimizeACL attempts to reduce the number of nACL rules in an nACL without changing the semantic.`, Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) error { - return nil + return optimization(cmd, args, acloptimizer.NewACLOptimizer, false) }, } + // flags + cmd.PersistentFlags().StringVarP(&args.firewallName, aclNameFlag, "n", "", "which nacl to optimize") + return cmd } diff --git a/cmd/subcmds/optimizeSG.go b/cmd/subcmds/optimizeSG.go index 1c903f83..9606234b 100644 --- a/cmd/subcmds/optimizeSG.go +++ b/cmd/subcmds/optimizeSG.go @@ -5,18 +5,27 @@ SPDX-License-Identifier: Apache-2.0 package subcmds -import "github.com/spf13/cobra" +import ( + "github.com/spf13/cobra" + + sgoptimizer "github.com/np-guard/vpc-network-config-synthesis/pkg/optimize/sg" +) + +const sgNameFlag = "sg-name" func NewOptimizeSGCommand(args *inArgs) *cobra.Command { cmd := &cobra.Command{ Use: "sg", - Short: "OptimizeSG is not supported yet", - Long: `OptimizeSG is not supported yet`, + Short: "OptimizeSG attempts to reduce the number of security group rules in a SG without changing the semantic.", + Long: `OptimizeSG attempts to reduce the number of security group rules in a SG without changing the semantic.`, Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) error { - return nil + return optimization(cmd, args, sgoptimizer.NewSGOptimizer, true) }, } + // flags + cmd.PersistentFlags().StringVarP(&args.firewallName, sgNameFlag, "n", "", "which security group to optimize") + return cmd } diff --git a/cmd/subcmds/output.go b/cmd/subcmds/output.go index aa817b7e..569d33e3 100644 --- a/cmd/subcmds/output.go +++ b/cmd/subcmds/output.go @@ -12,37 +12,30 @@ import ( "os" "path/filepath" + "github.com/np-guard/vpc-network-config-synthesis/pkg/io" "github.com/np-guard/vpc-network-config-synthesis/pkg/io/confio" - "github.com/np-guard/vpc-network-config-synthesis/pkg/io/csvio" - "github.com/np-guard/vpc-network-config-synthesis/pkg/io/mdio" "github.com/np-guard/vpc-network-config-synthesis/pkg/io/tfio" - "github.com/np-guard/vpc-network-config-synthesis/pkg/ir" ) const defaultFilePermission = 0o644 const defaultDirectoryPermission = 0o755 -func writeOutput(args *inArgs, collection ir.Collection, vpcNames []ir.ID) error { - if err := updateOutputFormat(args); err != nil { - return err - } - if args.outputDir != "" && args.outputFmt == apiOutputFormat { - return fmt.Errorf("-d cannot be used with format json") - } +func writeOutput(args *inArgs, collection ir.Collection, vpcNames []string, isSynth bool) error { if args.outputDir != "" { // create the directory if needed if err := os.MkdirAll(args.outputDir, defaultDirectoryPermission); err != nil { return err } } - if err := writeLocals(args, collection, vpcNames); err != nil { + + if err := writeLocals(args, vpcNames, collection); err != nil { return err } var data *bytes.Buffer var err error if args.outputDir == "" { - if data, err = writeCollection(args, collection, ""); err != nil { + if data, err = writeCollection(args, collection, "", isSynth); err != nil { return err } return writeToFile(args.outputFile, data) @@ -55,7 +48,7 @@ func writeOutput(args *inArgs, collection ir.Collection, vpcNames []ir.ID) error if args.prefix != "" { args.outputFile = args.outputDir + "/" + args.prefix + "_" + suffix } - if data, err = writeCollection(args, collection, vpc); err != nil { + if data, err = writeCollection(args, collection, vpc, isSynth); err != nil { return err } if err := writeToFile(args.outputFile, data); err != nil { @@ -65,53 +58,50 @@ func writeOutput(args *inArgs, collection ir.Collection, vpcNames []ir.ID) error return nil } -func writeCollection(args *inArgs, collection ir.Collection, vpc string) (*bytes.Buffer, error) { +func writeCollection(args *inArgs, collection ir.Collection, vpc string, isSynth bool) (*bytes.Buffer, error) { var data bytes.Buffer writer, err := pickWriter(args, &data) if err != nil { return nil, err } - if err := collection.Write(writer, vpc); err != nil { + if err := collection.Write(writer, vpc, isSynth); err != nil { return nil, err } return &data, nil } -func writeToFile(outputFile string, data *bytes.Buffer) error { - if outputFile == "" { - fmt.Println(data.String()) - return nil - } - return os.WriteFile(outputFile, data.Bytes(), defaultFilePermission) -} - func pickWriter(args *inArgs, data *bytes.Buffer) (ir.Writer, error) { w := bufio.NewWriter(data) switch args.outputFmt { case tfOutputFormat: return tfio.NewWriter(w), nil case csvOutputFormat: - return csvio.NewWriter(w), nil + return io.NewCSVWriter(w), nil case mdOutputFormat: - return mdio.NewWriter(w), nil - case apiOutputFormat: + return io.NewMDWriter(w), nil + case jsonOutputFormat: return confio.NewWriter(w, args.configFile) - default: - return nil, fmt.Errorf("bad output format: %q", args.outputFmt) } + return nil, fmt.Errorf("bad output format: %q", args.outputFmt) } -func writeLocals(args *inArgs, collection ir.Collection, vpcNames []ir.ID) error { - if !args.locals { +func writeToFile(outputFile string, data *bytes.Buffer) error { + if outputFile == "" { + fmt.Println(data.String()) return nil } - if args.outputFmt != tfOutputFormat { - return fmt.Errorf("--locals flag requires setting the output format to tf") - } + return os.WriteFile(outputFile, data.Bytes(), defaultFilePermission) +} - _, isACLCollection := collection.(*ir.ACLCollection) +func writeLocals(args *inArgs, vpcNames []ir.ID, collection ir.Collection) error { + if !args.locals { + return nil + } var data *bytes.Buffer var err error + + _, isACLCollection := collection.(*ir.ACLCollection) + if data, err = tfio.WriteLocals(vpcNames, isACLCollection); err != nil { return err } diff --git a/cmd/subcmds/outputFormat.go b/cmd/subcmds/outputFormat.go index 51a36c60..f435c43a 100644 --- a/cmd/subcmds/outputFormat.go +++ b/cmd/subcmds/outputFormat.go @@ -14,11 +14,11 @@ const ( tfOutputFormat = "tf" csvOutputFormat = "csv" mdOutputFormat = "md" - apiOutputFormat = "json" + jsonOutputFormat = "json" defaultOutputFormat = csvOutputFormat ) -var outputFormats = []string{tfOutputFormat, csvOutputFormat, mdOutputFormat, apiOutputFormat} +var outputFormats = []string{tfOutputFormat, csvOutputFormat, mdOutputFormat, jsonOutputFormat} func updateOutputFormat(args *inArgs) error { var err error @@ -40,7 +40,7 @@ func inferFormatUsingFilename(filename string) (string, error) { case strings.HasSuffix(filename, ".md"): return mdOutputFormat, nil case strings.HasSuffix(filename, ".json"): - return apiOutputFormat, nil + return jsonOutputFormat, nil default: return "", fmt.Errorf("bad output format") } diff --git a/cmd/subcmds/root.go b/cmd/subcmds/root.go index 281c66b5..98ff7973 100644 --- a/cmd/subcmds/root.go +++ b/cmd/subcmds/root.go @@ -14,7 +14,6 @@ import ( const ( configFlag = "config" - specFlag = "spec" outputFmtFlag = "format" outputFileFlag = "output-file" outputDirFlag = "output-dir" @@ -24,44 +23,53 @@ const ( ) type inArgs struct { - configFile string - specFile string - outputFmt string - outputFile string - outputDir string - prefix string - singleacl bool - locals bool + configFile string + specFile string + outputFmt string + outputFile string + outputDir string + prefix string + firewallName string + singleacl bool + locals bool } func NewRootCommand() *cobra.Command { args := &inArgs{} + // allow PersistentPreRunE + cobra.EnableTraverseRunHooks = true + rootCmd := &cobra.Command{ Use: "vpcgen", - Short: "Tool for automatic synthesis of VPC network configurations", - Long: `Tool for automatic synthesis of VPC network configurations, namely Network ACLs and Security Groups.`, + Short: "A tool for synthesizing and optimizing VPC network configurations", + Long: `A tool for synthesizing and optimizing VPC network configurations, namely Network ACLs and Security Groups.`, + PersistentPreRunE: func(cmd *cobra.Command, _ []string) error { + return validateFlags(args) + }, } + // flags rootCmd.PersistentFlags().StringVarP(&args.configFile, configFlag, "c", "", "JSON file containing a configuration object of existing resources") rootCmd.PersistentFlags().StringVarP(&args.outputFmt, outputFmtFlag, "f", "", "Output format; "+mustBeOneOf(outputFormats)) rootCmd.PersistentFlags().StringVarP(&args.outputFile, outputFileFlag, "o", "", "Write all generated resources to the specified file.") - rootCmd.PersistentFlags().StringVarP(&args.outputDir, outputDirFlag, "d", "", - "Write generated resources to files in the specified directory, one file per VPC.") - rootCmd.PersistentFlags().StringVarP(&args.prefix, prefixFlag, "p", "", "The prefix of the files that will be created.") rootCmd.PersistentFlags().BoolVarP(&args.locals, localsFlag, "l", false, "whether to generate a locals.tf file (only possible when the output format is tf)") - rootCmd.PersistentFlags().SortFlags = false + // flags set for all commands + rootCmd.PersistentFlags().SortFlags = false _ = rootCmd.MarkPersistentFlagRequired(configFlag) - rootCmd.MarkFlagsMutuallyExclusive(outputFileFlag, outputDirFlag) + // sub cmds rootCmd.AddCommand(NewSynthCommand(args)) - // Todo: add optimize command + rootCmd.AddCommand(NewOptimizeCommand(args)) + + // prevent Cobra from creating a default 'completion' command + rootCmd.CompletionOptions.DisableDefaultCmd = true - rootCmd.CompletionOptions.HiddenDefaultCmd = true - rootCmd.SetHelpCommand(&cobra.Command{Hidden: true}) // disable help command. should use --help flag instead + // disable help command. should use --help flag instead + rootCmd.SetHelpCommand(&cobra.Command{Hidden: true}) return rootCmd } diff --git a/cmd/subcmds/synth.go b/cmd/subcmds/synth.go index ef0f81d4..83eb348a 100644 --- a/cmd/subcmds/synth.go +++ b/cmd/subcmds/synth.go @@ -13,6 +13,8 @@ import ( "github.com/np-guard/vpc-network-config-synthesis/pkg/utils" ) +const specFlag = "spec" + func NewSynthCommand(args *inArgs) *cobra.Command { cmd := &cobra.Command{ Use: "synth", @@ -21,9 +23,16 @@ func NewSynthCommand(args *inArgs) *cobra.Command { --config and --spec parameters must be supplied.`, } + // flags cmd.PersistentFlags().StringVarP(&args.specFile, specFlag, "s", "", "JSON file containing spec file") + cmd.PersistentFlags().StringVarP(&args.outputDir, outputDirFlag, "d", "", + "Write generated resources to files in the specified directory, one file per VPC.") + cmd.PersistentFlags().StringVarP(&args.prefix, prefixFlag, "p", "", "The prefix of the files that will be created.") + + // flags settings _ = cmd.MarkPersistentFlagRequired(specFlag) + // sub cmds cmd.AddCommand(NewSynthACLCommand(args)) cmd.AddCommand(NewSynthSGCommand(args)) @@ -41,5 +50,5 @@ func synthesis(cmd *cobra.Command, args *inArgs, newSynthesizer func(*ir.Spec, b if err != nil { return err } - return writeOutput(args, collection, utils.MapKeys(spec.Defs.ConfigDefs.VPCs)) + return writeOutput(args, collection, utils.MapKeys(spec.Defs.ConfigDefs.VPCs), true) } diff --git a/cmd/subcmds/unmarshal.go b/cmd/subcmds/unmarshal.go index 5fa7c720..fcb1f76e 100644 --- a/cmd/subcmds/unmarshal.go +++ b/cmd/subcmds/unmarshal.go @@ -26,3 +26,10 @@ func unmarshal(args *inArgs) (*ir.Spec, error) { return model, nil } + +func parseCollection(args *inArgs, isSG bool) (ir.Collection, error) { + if isSG { + return confio.ReadSGs(args.configFile) + } + return confio.ReadACLs(args.configFile) +} diff --git a/cmd/subcmds/validateFlags.go b/cmd/subcmds/validateFlags.go new file mode 100644 index 00000000..be56f6fd --- /dev/null +++ b/cmd/subcmds/validateFlags.go @@ -0,0 +1,24 @@ +/* +Copyright 2023- IBM Inc. All Rights Reserved. +SPDX-License-Identifier: Apache-2.0 +*/ + +package subcmds + +import "fmt" + +func validateFlags(args *inArgs) error { + if args.outputDir != "" && args.outputFile != "" { + return fmt.Errorf("specifying both -d and -o is not allowed") + } + if err := updateOutputFormat(args); err != nil { + return err + } + if args.outputDir != "" && args.outputFmt == jsonOutputFormat { + return fmt.Errorf("-d cannot be used with format json") + } + if args.locals && args.outputFmt != tfOutputFormat { + return fmt.Errorf("--locals flag requires setting the output format to tf") + } + return nil +} diff --git a/go.mod b/go.mod index 2a404e56..25753169 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.23.0 require ( github.com/IBM/vpc-go-sdk v0.60.0 github.com/np-guard/cloud-resource-collector v0.15.0 - github.com/np-guard/models v0.5.0 + github.com/np-guard/models v0.5.1 github.com/spf13/cobra v1.8.1 ) diff --git a/go.sum b/go.sum index e4aac127..afa0f647 100644 --- a/go.sum +++ b/go.sum @@ -134,8 +134,8 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWb github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/np-guard/cloud-resource-collector v0.15.0 h1:jkmxql6D1uBr/qmSOsBzUgeDxlUXSCe7dBKfqfK+QZ4= github.com/np-guard/cloud-resource-collector v0.15.0/go.mod h1:klCHnNnuuVcCtGQHA7R1a8fqnvfMCk/5Jdld6V7sN2A= -github.com/np-guard/models v0.5.0 h1:P37gCg3RD23hZHymFWtthrF+mGIwyHJkWy0wIWIzokQ= -github.com/np-guard/models v0.5.0/go.mod h1:29M8utxinyUpYaDuIuOyCcMBf7EsMWZcIrRWCjFm0Bw= +github.com/np-guard/models v0.5.1 h1:qxewCB3cBLkBdcpMk05gKJkV1D7qkbteQdIXbN1juW0= +github.com/np-guard/models v0.5.1/go.mod h1:29M8utxinyUpYaDuIuOyCcMBf7EsMWZcIrRWCjFm0Bw= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= diff --git a/pkg/io/csvio/common.go b/pkg/io/common.go similarity index 77% rename from pkg/io/csvio/common.go rename to pkg/io/common.go index 41cd664d..4e4f9e33 100644 --- a/pkg/io/csvio/common.go +++ b/pkg/io/common.go @@ -3,33 +3,22 @@ Copyright 2023- IBM Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ -// Package csvio implements output of ACLs and security groups in CSV format -package csvio +package io import ( - "encoding/csv" "fmt" - "io" "strconv" "strings" + "github.com/np-guard/models/pkg/interval" "github.com/np-guard/models/pkg/netp" "github.com/np-guard/vpc-network-config-synthesis/pkg/ir" ) -// Writer implements ir.Writer -type Writer struct { - w *csv.Writer -} - -func NewWriter(w io.Writer) *Writer { - return &Writer{w: csv.NewWriter(w)} -} - const ( anyProtocol = "ALL" - nonIcmp = "-" // IBM cloud uses "—" + nonIcmp = "-" anyIcmpValue = "Any" ) @@ -40,6 +29,25 @@ func direction(d ir.Direction) string { return "Outbound" } +func printProtocolName(protocol netp.Protocol) string { + switch p := protocol.(type) { + case netp.ICMP: + return "ICMP" + case netp.TCPUDP: + return strings.ToUpper(string(p.ProtocolString())) + case netp.AnyProtocol: + return anyProtocol + } + return "" +} + +func printPorts(p interval.Interval) string { + if p.Equal(netp.AllPorts()) { + return "any port" + } + return fmt.Sprintf("ports %v-%v", p.Start(), p.End()) +} + func printICMPTypeCode(protocol netp.Protocol) string { p, ok := protocol.(netp.ICMP) if !ok { @@ -55,15 +63,3 @@ func printICMPTypeCode(protocol netp.Protocol) string { } return fmt.Sprintf("Type: %v, Code: %v", icmpType, icmpCode) } - -func printProtocolName(protocol netp.Protocol) string { - switch p := protocol.(type) { - case netp.ICMP: - return "ICMP" - case netp.TCPUDP: - return strings.ToUpper(string(p.ProtocolString())) - case netp.AnyProtocol: - return anyProtocol - } - return "" -} diff --git a/pkg/io/csvio/acl.go b/pkg/io/commonACL.go similarity index 52% rename from pkg/io/csvio/acl.go rename to pkg/io/commonACL.go index 643dfe38..9ce55f0e 100644 --- a/pkg/io/csvio/acl.go +++ b/pkg/io/commonACL.go @@ -3,43 +3,57 @@ Copyright 2023- IBM Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ -package csvio +package io import ( "errors" "fmt" "strconv" + "strings" - "github.com/np-guard/models/pkg/interval" "github.com/np-guard/models/pkg/netp" "github.com/np-guard/models/pkg/netset" "github.com/np-guard/vpc-network-config-synthesis/pkg/ir" ) -// Write prints an entire collection of acls as a single CSV table. -func (w *Writer) WriteACL(collection *ir.ACLCollection, vpc string) error { - if err := w.w.WriteAll(aclHeader()); err != nil { - return err - } - for _, subnet := range collection.SortedACLSubnets(vpc) { - vpcName := ir.VpcFromScopedResource(subnet) - aclTable, err := makeACLTable(collection.ACLs[vpcName][subnet], subnet) - if err != nil { - return err +func WriteACL(collection *ir.ACLCollection, vpc string) ([][]string, error) { + res := make([][]string, 0) + for _, vpcName := range collection.VpcNames() { + if vpc != vpcName && vpc != "" { + continue } - if err := w.w.WriteAll(aclTable); err != nil { - return err + for _, aclName := range collection.SortedACLNames(vpcName) { + aclTable, err := makeACLTable(collection.ACLs[vpcName][aclName]) + if err != nil { + return nil, err + } + res = append(res, aclTable...) } } - return nil + return res, nil } -func makeACLTable(t *ir.ACL, subnet string) ([][]string, error) { - rules := t.Rules() +func ACLHeader() [][]string { + return [][]string{{ + "Acl", + "Subnet", + "Direction", + "Rule priority", + "Allow or deny", + "Protocol", + "Source", + "Destination", + "Value", + "Description", + }} +} + +func makeACLTable(acl *ir.ACL) ([][]string, error) { + rules := acl.Rules() rows := make([][]string, len(rules)) for i, rule := range rules { - aclRow, err := makeACLRow(i+1, rule, t.Name(), subnet) + aclRow, err := makeACLRow(acl, i+1, rule) if err != nil { return nil, err } @@ -48,13 +62,6 @@ func makeACLTable(t *ir.ACL, subnet string) ([][]string, error) { return rows, nil } -func aclPort(p interval.Interval) string { - if p.Equal(netp.AllPorts()) { - return "any port" //nolint:goconst // independent decision for SG and ACL - } - return fmt.Sprintf("ports %v-%v", p.Start(), p.End()) -} - func action(a ir.Action) string { if a == ir.Deny { return "Deny" @@ -62,37 +69,22 @@ func action(a ir.Action) string { return "Allow" } -func aclHeader() [][]string { - return [][]string{{ - "Acl", - "Subnet", - "Direction", - "Rule priority", - "Allow or deny", - "Protocol", - "Source", - "Destination", - "Value", - "Description", - }} -} - -func makeACLRow(priority int, rule *ir.ACLRule, aclName, subnet string) ([]string, error) { - srcProtocol, err1 := printIP(rule.Source, rule.Protocol, true) - dstProtocol, err2 := printIP(rule.Destination, rule.Protocol, false) +func makeACLRow(acl *ir.ACL, priority int, rule *ir.ACLRule) ([]string, error) { + src, err1 := printIP(rule.Source, rule.Protocol, true) + dst, err2 := printIP(rule.Destination, rule.Protocol, false) if errors.Join(err1, err2) != nil { return nil, errors.Join(err1, err2) } return []string{ - aclName, - subnet, + acl.Name(), + strings.Join(acl.Subnets, ", "), direction(rule.Direction), strconv.Itoa(priority), action(rule.Action), printProtocolName(rule.Protocol), - srcProtocol, - dstProtocol, + src, + dst, printICMPTypeCode(rule.Protocol), rule.Explanation, }, nil @@ -107,13 +99,11 @@ func printIP(ip *netset.IPBlock, protocol netp.Protocol, isSource bool) (string, case netp.ICMP: return ipString, nil case netp.TCPUDP: - var r interval.Interval + r := p.DstPorts() if isSource { r = p.SrcPorts() - } else { - r = p.DstPorts() } - return fmt.Sprintf("%v, %v", ipString, aclPort(r)), nil + return fmt.Sprintf("%v, %v", ipString, printPorts(r)), nil case netp.AnyProtocol: return ipString, nil } diff --git a/pkg/io/csvio/sg.go b/pkg/io/commonSG.go similarity index 73% rename from pkg/io/csvio/sg.go rename to pkg/io/commonSG.go index ed91a1ef..021f5a57 100644 --- a/pkg/io/csvio/sg.go +++ b/pkg/io/commonSG.go @@ -3,37 +3,36 @@ Copyright 2023- IBM Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ -package csvio +package io import ( "errors" "fmt" - "github.com/np-guard/models/pkg/interval" "github.com/np-guard/models/pkg/netp" "github.com/np-guard/models/pkg/netset" "github.com/np-guard/vpc-network-config-synthesis/pkg/ir" ) -func (w *Writer) WriteSG(collection *ir.SGCollection, vpc string) error { - if err := w.w.WriteAll(sgHeader()); err != nil { - return err - } - for _, sgName := range collection.SortedSGNames(vpc) { - vpcName := ir.VpcFromScopedResource(string(sgName)) - sgTable, err := makeSGTable(collection.SGs[vpcName][sgName], sgName) - if err != nil { - return err +func WriteSG(collection *ir.SGCollection, vpc string) ([][]string, error) { + res := make([][]string, 0) + for _, vpcName := range collection.VpcNames() { + if vpc != vpcName && vpc != "" { + continue } - if err := w.w.WriteAll(sgTable); err != nil { - return err + for _, sgName := range collection.SortedSGNames(vpcName) { + sgTable, err := makeSGTable(collection.SGs[vpcName][sgName], sgName) + if err != nil { + return nil, err + } + res = append(res, sgTable...) } } - return nil + return res, nil } -func sgHeader() [][]string { +func SGHeader() [][]string { return [][]string{{ "SG", "Direction", @@ -45,6 +44,19 @@ func sgHeader() [][]string { }} } +func makeSGTable(t *ir.SG, sgName ir.SGName) ([][]string, error) { + rules := t.AllRules() + rows := make([][]string, len(rules)) + for i, rule := range rules { + sgRow, err := makeSGRow(rule, sgName) + if err != nil { + return nil, err + } + rows[i] = sgRow + } + return rows, nil +} + func makeSGRow(rule *ir.SGRule, sgName ir.SGName) ([]string, error) { remoteType, err1 := sgRemoteType(rule.Remote) remote, err2 := sgRemote(rule.Remote) @@ -64,28 +76,6 @@ func makeSGRow(rule *ir.SGRule, sgName ir.SGName) ([]string, error) { }, nil } -func makeSGTable(t *ir.SG, sgName ir.SGName) ([][]string, error) { - rules := t.AllRules() - rows := make([][]string, len(rules)) - for i, rule := range rules { - sgRow, err := makeSGRow(rule, sgName) - if err != nil { - return nil, err - } - rows[i] = sgRow - } - return rows, nil -} - -func sgPort(p interval.Interval) string { - switch { - case p.Start() == netp.MinPort && p.End() == netp.MaxPort: - return "any port" - default: - return fmt.Sprintf("ports %v-%v", p.Start(), p.End()) - } -} - func sgRemoteType(t ir.RemoteType) (string, error) { switch p := t.(type) { case *netset.IPBlock: @@ -118,7 +108,7 @@ func printProtocolParams(protocol netp.Protocol) (string, error) { case netp.ICMP: return printICMPTypeCode(protocol), nil case netp.TCPUDP: - return sgPort(p.DstPorts()), nil + return printPorts(p.DstPorts()), nil case netp.AnyProtocol: return "", nil } diff --git a/pkg/io/confio/acl.go b/pkg/io/confio/acl.go index ae5e7a7b..d4569cc2 100644 --- a/pkg/io/confio/acl.go +++ b/pkg/io/confio/acl.go @@ -18,8 +18,123 @@ import ( "github.com/np-guard/vpc-network-config-synthesis/pkg/utils" ) -func cidr(address *netset.IPBlock) *string { - return utils.Ptr(address.ToCidrListString()) +// WriteACL updates the given config_object file with synthesis/optimization results +func (w *Writer) WriteACL(collection *ir.ACLCollection, _ string, isSynth bool) error { + var err error + if isSynth { + err = makeACLs(w.model, collection) + } else { + err = updateACLs(w.model, collection) + } + if err != nil { + return err + } + globalIndex = 0 // making test results more predictable + return w.writeModel() +} + +// makeACLs calls updateSingleACL if we generated a single ACL, +// o.w. it calls updateACL +func makeACLs(model *configModel.ResourcesContainerModel, collection *ir.ACLCollection) error { + if len(model.SubnetList) == 0 { + return nil + } + subnet := model.SubnetList[0] + vpcName := *subnet.VPC.Name + aclName := ScopingString(vpcName, *subnet.Name) + + // decide if we are in a single-ACL mode + if _, ok := collection.ACLs[vpcName][aclName]; ok { + return makeACL(model, collection) + } + return makeSingleACL(model, collection) +} + +// updateACL writes all the generates nACLs to the config object +func makeACL(model *configModel.ResourcesContainerModel, collection *ir.ACLCollection) error { + for _, subnet := range model.SubnetList { + vpcName := *subnet.VPC.Name + aclName := ScopingString(vpcName, *subnet.Name) + + acl := collection.ACLs[vpcName][aclName] + aclItem, err := newACLItem(subnet, acl) + if err != nil { + return err + } + model.NetworkACLList = append(model.NetworkACLList, aclItem) + subnet.NetworkACL = newNACLRef(aclItem) + } + + return nil +} + +// updateACL writes the generated nACL to the config object +func makeSingleACL(model *configModel.ResourcesContainerModel, collection *ir.ACLCollection) error { + aclItem := &configModel.NetworkACL{} + var err error + + for i, subnet := range model.SubnetList { + vpcName := *subnet.VPC.Name + acl := collection.ACLs[vpcName][ScopingString(vpcName, "singleACL")] + + // if this is the first subnet being added to the ACL, add it to the list of network ACLs + // otherwise, add the subnet reference to the existing ACL item + if i == 0 { + aclItem, err = newACLItem(subnet, acl) + if err != nil { + return err + } + model.NetworkACLList = append(model.NetworkACLList, aclItem) + } else { + aclItem.Subnets = append(aclItem.Subnets, *subnetRef(subnet)) + } + subnet.NetworkACL = newNACLRef(aclItem) + } + return nil +} + +func newACLItem(subnet *configModel.Subnet, acl *ir.ACL) (*configModel.NetworkACL, error) { + ref := allocateRef() + rules, err := aclRules(acl) + if err != nil { + return nil, err + } + aclItem := configModel.NewNetworkACL(&vpcv1.NetworkACL{ + CRN: ref.CRN, + Href: ref.Href, + ID: ref.ID, + Name: utils.Ptr(ir.ChangeScoping(acl.Name())), + ResourceGroup: subnet.ResourceGroup, + Rules: rules, + Subnets: []vpcv1.SubnetReference{*subnetRef(subnet)}, + VPC: subnet.VPC, + }) + aclItem.Tags = []string{} + return aclItem, nil +} + +func aclRules(acl *ir.ACL) ([]vpcv1.NetworkACLRuleItemIntf, error) { + rules := acl.Rules() + ruleItems := make([]vpcv1.NetworkACLRuleItemIntf, len(rules)) + + var next *vpcv1.NetworkACLRuleReference + for i := len(ruleItems) - 1; i >= 0; i-- { + name := utils.Ptr(fmt.Sprintf("rule%v", i)) + ref := allocateRef() + current := &vpcv1.NetworkACLRuleReference{ + Name: name, + Href: ref.Href, + ID: ref.ID, + } + rule, err := makeACLRuleItem(rules[i], current, next) + if err != nil { + return nil, err + } + ruleItems[i] = rule + next = current + } + + return ruleItems, nil } func makeACLRuleItem(rule *ir.ACLRule, current, @@ -89,87 +204,6 @@ func makeACLRuleItem(rule *ir.ACLRule, current, } } -func aclRules(acl *ir.ACL) ([]vpcv1.NetworkACLRuleItemIntf, error) { - rules := acl.Rules() - ruleItems := make([]vpcv1.NetworkACLRuleItemIntf, len(rules)) - - var next *vpcv1.NetworkACLRuleReference - for i := len(ruleItems) - 1; i >= 0; i-- { - name := utils.Ptr(fmt.Sprintf("rule%v", i)) - ref := allocateRef() - current := &vpcv1.NetworkACLRuleReference{ - Name: name, - Href: ref.Href, - ID: ref.ID, - } - rule, err := makeACLRuleItem(rules[i], current, next) - if err != nil { - return nil, err - } - ruleItems[i] = rule - next = current - } - - return ruleItems, nil -} - -func updateACLList(model *configModel.ResourcesContainerModel, collection *ir.ACLCollection) error { - if len(model.SubnetList) == 0 { - return nil - } - subnet := model.SubnetList[0] - vpcName := *subnet.VPC.Name - aclName := ScopingString(vpcName, *subnet.Name) - - // decide if we are in a single-ACL mode - if _, ok := collection.ACLs[vpcName][aclName]; ok { - return updateACL(model, collection) - } - return updateSingleACL(model, collection) -} - -func updateACL(model *configModel.ResourcesContainerModel, collection *ir.ACLCollection) error { - for _, subnet := range model.SubnetList { - vpcName := *subnet.VPC.Name - aclName := ScopingString(vpcName, *subnet.Name) - - acl := collection.ACLs[vpcName][aclName] - aclItem, err := newACLItem(subnet, acl) // create a new ACL item for the subnet - if err != nil { - return err - } - model.NetworkACLList = append(model.NetworkACLList, aclItem) - subnet.NetworkACL = newNACLRef(aclItem) - } - globalIndex = 0 // making test results more predictable - return nil -} - -func updateSingleACL(model *configModel.ResourcesContainerModel, collection *ir.ACLCollection) error { - aclItem := &configModel.NetworkACL{} - var err error - - for i, subnet := range model.SubnetList { - vpcName := *subnet.VPC.Name - acl := collection.ACLs[vpcName][ScopingString(vpcName, "singleACL")] - - // if this is the first subnet being added to the ACL, add it to the list of network ACLs - // otherwise, add the subnet reference to the existing ACL item - if i == 0 { - aclItem, err = newACLItem(subnet, acl) - if err != nil { - return err - } - model.NetworkACLList = append(model.NetworkACLList, aclItem) - } else { - aclItem.Subnets = append(aclItem.Subnets, *subnetRef(subnet)) - } - subnet.NetworkACL = newNACLRef(aclItem) - } - globalIndex = 0 // making test results more predictable - return nil -} - func newNACLRef(aclItem *configModel.NetworkACL) *vpcv1.NetworkACLReference { return &vpcv1.NetworkACLReference{ ID: aclItem.ID, @@ -179,26 +213,6 @@ func newNACLRef(aclItem *configModel.NetworkACL) *vpcv1.NetworkACLReference { } } -func newACLItem(subnet *configModel.Subnet, acl *ir.ACL) (*configModel.NetworkACL, error) { - ref := allocateRef() - rules, err := aclRules(acl) - if err != nil { - return nil, err - } - aclItem := configModel.NewNetworkACL(&vpcv1.NetworkACL{ - CRN: ref.CRN, - Href: ref.Href, - ID: ref.ID, - Name: utils.Ptr(ir.ChangeScoping(acl.Name())), - ResourceGroup: subnet.ResourceGroup, - Rules: rules, - Subnets: []vpcv1.SubnetReference{*subnetRef(subnet)}, - VPC: subnet.VPC, - }) - aclItem.Tags = []string{} - return aclItem, nil -} - func subnetRef(subnet *configModel.Subnet) *vpcv1.SubnetReference { return &vpcv1.SubnetReference{ Name: subnet.Name, @@ -209,9 +223,6 @@ func subnetRef(subnet *configModel.Subnet) *vpcv1.SubnetReference { } } -func (w *Writer) WriteACL(collection *ir.ACLCollection, _ string) error { - if err := updateACLList(w.model, collection); err != nil { - return err - } - return w.writeModel() +func cidr(address *netset.IPBlock) *string { + return utils.Ptr(address.ToCidrListString()) } diff --git a/pkg/io/confio/optimizeACL.go b/pkg/io/confio/optimizeACL.go new file mode 100644 index 00000000..6f24bed6 --- /dev/null +++ b/pkg/io/confio/optimizeACL.go @@ -0,0 +1,35 @@ +/* +Copyright 2023- IBM Inc. All Rights Reserved. +SPDX-License-Identifier: Apache-2.0 +*/ + +package confio + +import ( + "github.com/IBM/vpc-go-sdk/vpcv1" + configModel "github.com/np-guard/cloud-resource-collector/pkg/ibm/datamodel" + + "github.com/np-guard/vpc-network-config-synthesis/pkg/ir" +) + +func updateACLs(model *configModel.ResourcesContainerModel, collection *ir.ACLCollection) error { + for _, acl := range model.NetworkACLList { + if acl.Name == nil || acl.VPC == nil || acl.VPC.Name == nil { + continue + } + if err := updateACL(&acl.NetworkACL, collection.ACLs[*acl.VPC.Name][*acl.VPC.Name]); err != nil { + return err + } + } + return nil +} + +func updateACL(acl *vpcv1.NetworkACL, optimizedACL *ir.ACL) error { + optimizedRules := optimizedACL.Rules() + if len(optimizedRules) >= len(acl.Rules) { + return nil + } + rules, err := aclRules(optimizedACL) + acl.Rules = rules + return err +} diff --git a/pkg/io/confio/optimizeSG.go b/pkg/io/confio/optimizeSG.go new file mode 100644 index 00000000..b95d53f7 --- /dev/null +++ b/pkg/io/confio/optimizeSG.go @@ -0,0 +1,57 @@ +/* +Copyright 2023- IBM Inc. All Rights Reserved. +SPDX-License-Identifier: Apache-2.0 +*/ + +package confio + +import ( + "github.com/IBM/vpc-go-sdk/vpcv1" + + configModel "github.com/np-guard/cloud-resource-collector/pkg/ibm/datamodel" + + "github.com/np-guard/vpc-network-config-synthesis/pkg/ir" +) + +// updateSGs updates the config object file with the optimized SG rules +func updateSGs(model *configModel.ResourcesContainerModel, collection *ir.SGCollection) error { + sgRefMap := parseSGRefMap(model) + for _, sg := range model.SecurityGroupList { + if sg.Name == nil || sg.VPC == nil || sg.VPC.Name == nil { + continue + } + if err := updateSG(&sg.SecurityGroup, collection.SGs[*sg.VPC.Name][ir.SGName(*sg.Name)], sgRefMap); err != nil { + return err + } + } + return nil +} + +func updateSG(sg *vpcv1.SecurityGroup, optimizedSG *ir.SG, sgRefMap map[string]*vpcv1.SecurityGroupRuleRemoteSecurityGroupReference) error { + optimizedRules := optimizedSG.AllRules() + if len(optimizedRules) >= len(sg.Rules) { + return nil + } + sg.Rules = make([]vpcv1.SecurityGroupRuleIntf, len(optimizedRules)) + for i, rule := range optimizedRules { + r, err := makeSGRuleItem(sgRefMap, rule, i) + if err != nil { + return err + } + sg.Rules[i] = r + } + return nil +} + +func parseSGRefMap(model *configModel.ResourcesContainerModel) map[string]*vpcv1.SecurityGroupRuleRemoteSecurityGroupReference { + res := make(map[string]*vpcv1.SecurityGroupRuleRemoteSecurityGroupReference) + for _, sg := range model.SecurityGroupList { + res[*sg.Name] = &vpcv1.SecurityGroupRuleRemoteSecurityGroupReference{ + ID: sg.ID, + CRN: sg.CRN, + Href: sg.Href, + Name: sg.Name, + } + } + return res +} diff --git a/pkg/io/confio/parse_acls.go b/pkg/io/confio/parse_acls.go new file mode 100644 index 00000000..e0b923dc --- /dev/null +++ b/pkg/io/confio/parse_acls.go @@ -0,0 +1,161 @@ +/* +Copyright 2023- IBM Inc. All Rights Reserved. +SPDX-License-Identifier: Apache-2.0 +*/ + +package confio + +import ( + "errors" + "fmt" + "log" + + "github.com/IBM/vpc-go-sdk/vpcv1" + + "github.com/np-guard/models/pkg/netp" + "github.com/np-guard/models/pkg/netset" + + "github.com/np-guard/vpc-network-config-synthesis/pkg/ir" +) + +// ReadACLs translates ACLs from a config_object file to ir.ACLCollection +func ReadACLs(filename string) (*ir.ACLCollection, error) { + config, err := readModel(filename) + if err != nil { + return nil, err + } + + result := ir.NewACLCollection() + for i, acl := range config.NetworkACLList { + if acl.Name == nil || acl.VPC == nil || acl.VPC.Name == nil { + log.Printf("Warning: missing acl/VPC name in acl at index %d\n", i) + continue + } + inbound, outbound, err := translateACLRules(&acl.NetworkACL) + if err != nil { + return nil, err + } + vpcName := *acl.VPC.Name + if result.ACLs[vpcName] == nil { + result.ACLs[vpcName] = make(map[string]*ir.ACL) + } + result.ACLs[vpcName][*acl.Name] = &ir.ACL{ACLName: *acl.Name, + Subnets: parseAttachedSubnets(&acl.NetworkACL), + Inbound: inbound, + Outbound: outbound, + } + } + return result, nil +} + +func translateACLRules(acl *vpcv1.NetworkACL) (inbound, outbound []*ir.ACLRule, err error) { + inbound = make([]*ir.ACLRule, 0) + outbound = make([]*ir.ACLRule, 0) + for index := range acl.Rules { + rule, err := translateACLRule(acl, index) + if err != nil { + return nil, nil, err + } + if rule.Direction == ir.Inbound { + inbound = append(inbound, rule) + } else { + outbound = append(outbound, rule) + } + } + return inbound, outbound, nil +} + +func translateACLRule(acl *vpcv1.NetworkACL, i int) (*ir.ACLRule, error) { + switch r := acl.Rules[i].(type) { + case *vpcv1.NetworkACLRuleItemNetworkACLRuleProtocolAll: + return translateACLRuleProtocolAll(r) + case *vpcv1.NetworkACLRuleItemNetworkACLRuleProtocolTcpudp: + return translateACLRuleProtocolTCPUDP(r) + case *vpcv1.NetworkACLRuleItemNetworkACLRuleProtocolIcmp: + return translateACLRuleProtocolIcmp(r) + } + return nil, fmt.Errorf("error parsing rule number %d in acl %s in VPC %s", i, *acl.Name, *acl.VPC.Name) +} + +func translateACLRuleProtocolAll(rule *vpcv1.NetworkACLRuleItemNetworkACLRuleProtocolAll) (*ir.ACLRule, error) { + action, err1 := translateAction(rule.Action) + direction, err2 := translateDirection(*rule.Direction) + src, err3 := translateResource(rule.Source) + dst, err4 := translateResource(rule.Destination) + if err := errors.Join(err1, err2, err3, err4); err != nil { + return nil, err + } + return &ir.ACLRule{ + Action: action, + Direction: direction, + Source: src, + Destination: dst, + Protocol: netp.AnyProtocol{}, + }, nil +} + +func translateACLRuleProtocolTCPUDP(rule *vpcv1.NetworkACLRuleItemNetworkACLRuleProtocolTcpudp) (*ir.ACLRule, error) { + action, err1 := translateAction(rule.Action) + direction, err2 := translateDirection(*rule.Direction) + src, err3 := translateResource(rule.Source) + dst, err4 := translateResource(rule.Destination) + protocol, err5 := translateProtocolTCPUDP(*rule.Protocol, rule.DestinationPortMin, rule.DestinationPortMax) + if err := errors.Join(err1, err2, err3, err4, err5); err != nil { + return nil, err + } + + return &ir.ACLRule{ + Action: action, + Direction: direction, + Source: src, + Destination: dst, + Protocol: protocol, + }, nil +} + +func translateACLRuleProtocolIcmp(rule *vpcv1.NetworkACLRuleItemNetworkACLRuleProtocolIcmp) (*ir.ACLRule, error) { + action, err1 := translateAction(rule.Action) + direction, err2 := translateDirection(*rule.Direction) + src, err3 := translateResource(rule.Source) + dst, err4 := translateResource(rule.Destination) + protocol, err5 := netp.ICMPFromTypeAndCode64WithoutRFCValidation(rule.Type, rule.Code) + if err := errors.Join(err1, err2, err3, err4, err5); err != nil { + return nil, err + } + + return &ir.ACLRule{ + Action: action, + Direction: direction, + Source: src, + Destination: dst, + Protocol: protocol, + }, nil +} + +func translateAction(action *string) (ir.Action, error) { + if *action == vpcv1.NetworkACLRuleItemNetworkACLRuleProtocolAllActionAllowConst { + return ir.Allow, nil + } else if *action == vpcv1.NetworkACLRuleItemNetworkACLRuleProtocolAllActionDenyConst { + return ir.Deny, nil + } + return ir.Deny, fmt.Errorf("an nACL rule action must be either allow or deny") +} + +func translateResource(ipAddrs *string) (*netset.IPBlock, error) { + return netset.IPBlockFromCidrOrAddress(*ipAddrs) +} + +func parseAttachedSubnets(acl *vpcv1.NetworkACL) []string { + if len(acl.Subnets) == 0 { + log.Printf("Warning: nACL %s does not have attached subnets", *acl.Name) + } + res := make([]string, 0) + for i, subnet := range acl.Subnets { + if subnet.Name != nil { + res = append(res, *subnet.Name) + } else { + log.Printf("Warning: error translating subnet %d in %s nACL", i, *acl.Name) + } + } + return res +} diff --git a/pkg/io/confio/parse_defs.go b/pkg/io/confio/parse_defs.go index 3b2705d9..86ba8a95 100644 --- a/pkg/io/confio/parse_defs.go +++ b/pkg/io/confio/parse_defs.go @@ -41,10 +41,6 @@ func ReadDefs(filename string) (*ir.ConfigDefs, error) { if err != nil { return nil, err } - err = validateVpcs(vpcs) - if err != nil { - return nil, err - } return &ir.ConfigDefs{ VPCs: vpcs, @@ -69,7 +65,7 @@ func parseVPCs(config *configModel.ResourcesContainerModel) (map[ir.ID]*ir.VPCDe } VPCs[*vpc.Name] = &ir.VPCDetails{AddressPrefixes: addressPrefixes} } - return VPCs, nil + return VPCs, validateVpcs(VPCs) } func parseSubnets(config *configModel.ResourcesContainerModel) (map[ir.ID]*ir.SubnetDetails, error) { diff --git a/pkg/io/confio/parse_sgs.go b/pkg/io/confio/parse_sgs.go new file mode 100644 index 00000000..840317dc --- /dev/null +++ b/pkg/io/confio/parse_sgs.go @@ -0,0 +1,172 @@ +/* +Copyright 2023- IBM Inc. All Rights Reserved. +SPDX-License-Identifier: Apache-2.0 +*/ + +package confio + +import ( + "errors" + "fmt" + "log" + + "github.com/IBM/vpc-go-sdk/vpcv1" + + "github.com/np-guard/models/pkg/netp" + "github.com/np-guard/models/pkg/netset" + + "github.com/np-guard/vpc-network-config-synthesis/pkg/ir" + "github.com/np-guard/vpc-network-config-synthesis/pkg/utils" +) + +// ReadSG translates SGs from a config_object file to map[ir.SGName]*SG +func ReadSGs(filename string) (*ir.SGCollection, error) { + config, err := readModel(filename) + if err != nil { + return nil, err + } + + result := ir.NewSGCollection() + for i, sg := range config.SecurityGroupList { + if sg.Name == nil || sg.VPC == nil || sg.VPC.Name == nil { + log.Printf("Warning: missing SG/VPC name in sg at index %d\n", i) + continue + } + inbound, outbound, err := translateSGRules(&sg.SecurityGroup) + if err != nil { + return nil, err + } + vpcName := *sg.VPC.Name + if result.SGs[vpcName] == nil { + result.SGs[vpcName] = make(map[ir.SGName]*ir.SG) + } + result.SGs[vpcName][ir.SGName(*sg.Name)] = &ir.SG{SGName: ir.SGName(*sg.Name), + InboundRules: inbound, + OutboundRules: outbound, + Targets: translateTargets(&sg.SecurityGroup), + } + } + return result, nil +} + +// parse security rules, splitted into ingress and egress rules +func translateSGRules(sg *vpcv1.SecurityGroup) (ingressRules, egressRules map[string][]*ir.SGRule, err error) { + ingressRules = make(map[string][]*ir.SGRule) + egressRules = make(map[string][]*ir.SGRule) + for index := range sg.Rules { + rule, err := translateSGRule(sg, index) + if err != nil { + return nil, nil, err + } + local := rule.Local.String() + if rule.Direction == ir.Inbound { + ingressRules[local] = append(ingressRules[local], rule) + } else { + egressRules[local] = append(egressRules[local], rule) + } + } + return ingressRules, egressRules, nil +} + +// translateSGRule translates a security group rule to ir.SGRule +func translateSGRule(sg *vpcv1.SecurityGroup, index int) (sgRule *ir.SGRule, err error) { + switch r := sg.Rules[index].(type) { + case *vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolAll: + return translateSGRuleProtocolAll(r) + case *vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolTcpudp: + return translateSGRuleProtocolTCPUDP(r) + case *vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolIcmp: + return translateSGRuleProtocolIcmp(r) + } + return nil, fmt.Errorf("error parsing rule number %d in sg %s in VPC %s", index, *sg.Name, *sg.VPC.Name) +} + +func translateSGRuleProtocolAll(rule *vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolAll) (sgRule *ir.SGRule, err error) { + direction, err1 := translateDirection(*rule.Direction) + remote, err2 := translateRemote(rule.Remote) + local, err3 := translateLocal(rule.Local) + if err := errors.Join(err1, err2, err3); err != nil { + return nil, err + } + return &ir.SGRule{Direction: direction, Remote: remote, Protocol: netp.AnyProtocol{}, Local: local}, nil +} + +func translateSGRuleProtocolTCPUDP(rule *vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolTcpudp) (sgRule *ir.SGRule, err error) { + direction, err1 := translateDirection(*rule.Direction) + remote, err2 := translateRemote(rule.Remote) + local, err3 := translateLocal(rule.Local) + protocol, err4 := translateProtocolTCPUDP(*rule.Protocol, rule.PortMin, rule.PortMax) + if err := errors.Join(err1, err2, err3, err4); err != nil { + return nil, err + } + return &ir.SGRule{Direction: direction, Remote: remote, Protocol: protocol, Local: local}, nil +} + +func translateSGRuleProtocolIcmp(rule *vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolIcmp) (sgRule *ir.SGRule, err error) { + direction, err1 := translateDirection(*rule.Direction) + remote, err2 := translateRemote(rule.Remote) + local, err3 := translateLocal(rule.Local) + protocol, err4 := netp.ICMPFromTypeAndCode64WithoutRFCValidation(rule.Type, rule.Code) + if err := errors.Join(err1, err2, err3, err4); err != nil { + return nil, err + } + return &ir.SGRule{Direction: direction, Remote: remote, Protocol: protocol, Local: local}, nil +} + +func translateDirection(direction string) (ir.Direction, error) { + if direction == "inbound" { + return ir.Inbound, nil + } else if direction == "outbound" { + return ir.Outbound, nil + } + return ir.Inbound, fmt.Errorf("a firewall rule direction must be either inbound or outbound") +} + +func translateRemote(remote vpcv1.SecurityGroupRuleRemoteIntf) (ir.RemoteType, error) { + if r, ok := remote.(*vpcv1.SecurityGroupRuleRemote); ok { + switch { + case r.CIDRBlock != nil: + return netset.IPBlockFromCidr(*r.CIDRBlock) + case r.Address != nil: + return netset.IPBlockFromIPAddress(*r.Address) + case r.Name != nil: + return ir.SGName(*r.Name), nil + } + } + return nil, fmt.Errorf("unexpected SG rule remote") +} + +func translateLocal(local vpcv1.SecurityGroupRuleLocalIntf) (*netset.IPBlock, error) { + if l, ok := local.(*vpcv1.SecurityGroupRuleLocal); ok { + if l.CIDRBlock != nil { + return netset.IPBlockFromCidr(*l.CIDRBlock) + } + if l.Address != nil { + return netset.IPBlockFromIPAddress(*l.Address) + } + } + return nil, fmt.Errorf("error parsing Local field") +} + +// translate SG targets +func translateTargets(sg *vpcv1.SecurityGroup) []string { + if len(sg.Targets) == 0 { + log.Printf("Warning: Security Groups %s does not have attached resources", *sg.Name) + } + res := make([]string, 0) + for i := range sg.Targets { + if t, ok := sg.Targets[i].(*vpcv1.SecurityGroupTargetReference); ok && t.Name != nil { + res = append(res, *t.Name) + } else { + log.Printf("Warning: error translating target %d in %s Security Group", i, *sg.Name) + } + } + return res +} + +func translateProtocolTCPUDP(protocolName string, portMin, portMax *int64) (netp.Protocol, error) { + isTCP := protocolName == vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolTcpudpProtocolTCPConst + minDstPort := utils.GetProperty(portMin, netp.MinPort) + maxDstPort := utils.GetProperty(portMax, netp.MaxPort) + return netp.NewTCPUDP(isTCP, netp.MinPort, netp.MaxPort, int(minDstPort), int(maxDstPort)) +} diff --git a/pkg/io/confio/sg.go b/pkg/io/confio/sg.go index e4b74be7..fbbdd9f8 100644 --- a/pkg/io/confio/sg.go +++ b/pkg/io/confio/sg.go @@ -54,7 +54,7 @@ func sgRemote(nameToSGRemoteRef map[string]*vpcv1.SecurityGroupRuleRemoteSecurit st := rule.Remote.String() switch t := rule.Remote.(type) { case *netset.IPBlock: - if ipString := t.ToIPAddressString(); ipString != "" { // single IP address + if t.IsSingleIPAddress() { // single IP address return &vpcv1.SecurityGroupRuleRemoteIP{ Address: &st, } @@ -72,13 +72,20 @@ func makeSGRuleItem(nameToSGRemoteRef map[string]*vpcv1.SecurityGroupRuleRemoteS rule *ir.SGRule, i int) (vpcv1.SecurityGroupRuleIntf, error) { iPVersion := utils.Ptr(ipv4Const) direction := direction(rule.Direction) - cidrAll := netset.CidrAll - local := &vpcv1.SecurityGroupRuleLocal{ - CIDRBlock: &cidrAll, - } ref := allocateRef() remote := sgRemote(nameToSGRemoteRef, rule) + var local vpcv1.SecurityGroupRuleLocalIntf + if rule.Local.IsSingleIPAddress() { + local = &vpcv1.SecurityGroupRuleLocalIP{ + Address: utils.Ptr(rule.Local.FirstIPAddress()), + } + } else { + local = &vpcv1.SecurityGroupRuleLocalCIDR{ + CIDRBlock: utils.Ptr(rule.Local.ToCidrList()[0]), + } + } + switch p := rule.Protocol.(type) { case netp.TCPUDP: data := tcpudp(p) @@ -245,7 +252,7 @@ func updateSGEndpointGW(model *configModel.ResourcesContainerModel, collection * return nil } -func updateSG(model *configModel.ResourcesContainerModel, collection *ir.SGCollection) error { +func writeSGs(model *configModel.ResourcesContainerModel, collection *ir.SGCollection) error { nameToSGRemoteRef := make(map[string]*vpcv1.SecurityGroupRuleRemoteSecurityGroupReference) idToSGIndex := make(map[string]int, len(model.SecurityGroupList)) for i := range model.SecurityGroupList { @@ -254,13 +261,19 @@ func updateSG(model *configModel.ResourcesContainerModel, collection *ir.SGColle err1 := updateSGInstances(model, collection, nameToSGRemoteRef, idToSGIndex) err2 := updateSGEndpointGW(model, collection, nameToSGRemoteRef, idToSGIndex) - globalIndex = 0 // making test results more predictable return errors.Join(err1, err2) } -func (w *Writer) WriteSG(collection *ir.SGCollection, _ string) error { - if err := updateSG(w.model, collection); err != nil { +func (w *Writer) WriteSG(collection *ir.SGCollection, _ string, isSynth bool) error { + var err error + if isSynth { + err = writeSGs(w.model, collection) + } else { + err = updateSGs(w.model, collection) + } + if err != nil { return err } + globalIndex = 0 // making test results more predictable return w.writeModel() } diff --git a/pkg/io/csvWriter.go b/pkg/io/csvWriter.go new file mode 100644 index 00000000..e583ca45 --- /dev/null +++ b/pkg/io/csvWriter.go @@ -0,0 +1,38 @@ +/* +Copyright 2023- IBM Inc. All Rights Reserved. +SPDX-License-Identifier: Apache-2.0 +*/ + +package io + +import ( + "encoding/csv" + "io" + + "github.com/np-guard/vpc-network-config-synthesis/pkg/ir" +) + +// CSVWriter implements ir.Writer +type CSVWriter struct { + w *csv.Writer +} + +func NewCSVWriter(w io.Writer) *CSVWriter { + return &CSVWriter{w: csv.NewWriter(w)} +} + +func (w *CSVWriter) WriteSG(collection *ir.SGCollection, vpc string, _ bool) error { + sgTable, err := WriteSG(collection, vpc) + if err != nil { + return err + } + return w.w.WriteAll(append(SGHeader(), sgTable...)) +} + +func (w *CSVWriter) WriteACL(collection *ir.ACLCollection, vpc string, _ bool) error { + aclTable, err := WriteACL(collection, vpc) + if err != nil { + return err + } + return w.w.WriteAll(append(ACLHeader(), aclTable...)) +} diff --git a/pkg/io/mdWriter.go b/pkg/io/mdWriter.go new file mode 100644 index 00000000..94b18553 --- /dev/null +++ b/pkg/io/mdWriter.go @@ -0,0 +1,71 @@ +/* +Copyright 2023- IBM Inc. All Rights Reserved. +SPDX-License-Identifier: Apache-2.0 +*/ + +package io + +import ( + "bufio" + "io" + "strings" + + "github.com/np-guard/vpc-network-config-synthesis/pkg/ir" +) + +const ( + sgColsNum = 7 + aclColsNum = 10 + + leftAlign = " :--- " + separator = " | " +) + +// MDWriter implements ir.Writer +type MDWriter struct { + w *bufio.Writer +} + +func NewMDWriter(w io.Writer) *MDWriter { + return &MDWriter{w: bufio.NewWriter(w)} +} + +func (w *MDWriter) WriteSG(collection *ir.SGCollection, vpc string, _ bool) error { + sgTable, err := WriteSG(collection, vpc) + if err != nil { + return err + } + return w.writeAll(append(append(SGHeader(), addAlighns(sgColsNum)...), sgTable...)) +} + +func (w *MDWriter) WriteACL(collection *ir.ACLCollection, vpc string, _ bool) error { + aclTable, err := WriteACL(collection, vpc) + if err != nil { + return err + } + return w.writeAll(append(append(ACLHeader(), addAlighns(aclColsNum)...), aclTable...)) +} + +func (w *MDWriter) writeAll(rows [][]string) error { + for _, row := range rows { + if _, err := w.w.WriteString(separator); err != nil { + return err + } + if _, err := w.w.WriteString(strings.Join(row, separator)); err != nil { + return err + } + if _, err := w.w.WriteString(separator + "\n"); err != nil { + return err + } + } + w.w.Flush() + return nil +} + +func addAlighns(n int) [][]string { + res := make([]string, n) + for i := range n { + res[i] = leftAlign + } + return [][]string{res} +} diff --git a/pkg/io/mdio/acl.go b/pkg/io/mdio/acl.go deleted file mode 100644 index 17f2b2ee..00000000 --- a/pkg/io/mdio/acl.go +++ /dev/null @@ -1,138 +0,0 @@ -/* -Copyright 2023- IBM Inc. All Rights Reserved. -SPDX-License-Identifier: Apache-2.0 -*/ - -package mdio - -import ( - "errors" - "fmt" - "strconv" - - "github.com/np-guard/models/pkg/interval" - "github.com/np-guard/models/pkg/netp" - "github.com/np-guard/models/pkg/netset" - - "github.com/np-guard/vpc-network-config-synthesis/pkg/ir" -) - -// Write prints an entire collection of acls as a single MD table. -func (w *Writer) WriteACL(collection *ir.ACLCollection, vpc string) error { - if err := w.writeAll(aclHeader()); err != nil { - return err - } - for _, subnet := range collection.SortedACLSubnets(vpc) { - vpcName := ir.VpcFromScopedResource(subnet) - aclTable, err := makeACLTable(collection.ACLs[vpcName][subnet], subnet) - if err != nil { - return err - } - if err := w.writeAll(aclTable); err != nil { - return err - } - } - return nil -} - -func makeACLTable(t *ir.ACL, subnet string) ([][]string, error) { - rules := t.Rules() - rows := make([][]string, len(rules)) - for i, rule := range rules { - aclRow, err := makeACLRow(i+1, rule, t.Name(), subnet) - if err != nil { - return nil, err - } - rows[i] = aclRow - } - return rows, nil -} - -func aclPort(p interval.Interval) string { - if p.Equal(netp.AllPorts()) { - return "any port" //nolint:goconst // independent decision for SG and ACL - } - return fmt.Sprintf("ports %v-%v", p.Start(), p.End()) -} - -func action(a ir.Action) string { - if a == ir.Deny { - return "Deny" - } - return "Allow" -} - -func aclHeader() [][]string { - return [][]string{{ - "", - "Acl", - "Subnet", - "Direction", - "Rule priority", - "Allow or deny", - "Protocol", - "Source", - "Destination", - "Value", - "Description", - "", - }, { - "", - leftAlign, - leftAlign, - leftAlign, - leftAlign, - leftAlign, - leftAlign, - leftAlign, - leftAlign, - leftAlign, - leftAlign, - "", - }} -} - -func makeACLRow(priority int, rule *ir.ACLRule, aclName, subnet string) ([]string, error) { - srcProtocol, err1 := printIP(rule.Source, rule.Protocol, true) - dstProtocol, err2 := printIP(rule.Destination, rule.Protocol, false) - if err := errors.Join(err1, err2); err != nil { - return nil, err - } - - return []string{ - "", - aclName, - subnet, - direction(rule.Direction), - strconv.Itoa(priority), - action(rule.Action), - printProtocolName(rule.Protocol), - srcProtocol, - dstProtocol, - printICMPTypeCode(rule.Protocol), - rule.Explanation, - "", - }, nil -} - -func printIP(ip *netset.IPBlock, protocol netp.Protocol, isSource bool) (string, error) { - ipString := ip.String() - if ip.Equal(netset.GetCidrAll()) { - ipString = "Any IP" //nolint:goconst // independent decision for SG and ACL - } - switch p := protocol.(type) { - case netp.ICMP: - return ipString, nil - case netp.TCPUDP: - var r interval.Interval - if isSource { - r = p.SrcPorts() - } else { - r = p.DstPorts() - } - return fmt.Sprintf("%v, %v", ipString, aclPort(r)), nil - case netp.AnyProtocol: - return ipString, nil - } - return "", fmt.Errorf("impossible protocol %T", protocol) -} diff --git a/pkg/io/mdio/common.go b/pkg/io/mdio/common.go deleted file mode 100644 index abfb24a8..00000000 --- a/pkg/io/mdio/common.go +++ /dev/null @@ -1,82 +0,0 @@ -/* -Copyright 2023- IBM Inc. All Rights Reserved. -SPDX-License-Identifier: Apache-2.0 -*/ - -// Package mdio implements output of ACLs and security groups in CSV format -package mdio - -import ( - "bufio" - "fmt" - "io" - "strconv" - "strings" - - "github.com/np-guard/models/pkg/netp" - - "github.com/np-guard/vpc-network-config-synthesis/pkg/ir" -) - -const leftAlign = " :--- " - -// Writer implements ir.Writer -type Writer struct { - w *bufio.Writer -} - -func NewWriter(w io.Writer) *Writer { - return &Writer{w: bufio.NewWriter(w)} -} - -func (w *Writer) writeAll(rows [][]string) error { - for _, row := range rows { - _, err := w.w.WriteString(strings.Join(row, " | ") + "\n") - if err != nil { - return err - } - } - w.w.Flush() - return nil -} - -const ( - anyProtocol = "ALL" - nonIcmp = "-" - anyIcmpValue = "Any" -) - -func direction(d ir.Direction) string { - if d == ir.Inbound { - return "Inbound" - } - return "Outbound" -} - -func printICMPTypeCode(protocol netp.Protocol) string { - p, ok := protocol.(netp.ICMP) - if !ok { - return nonIcmp - } - icmpType := anyIcmpValue - icmpCode := anyIcmpValue - if typeCode := p.ICMPTypeCode(); typeCode != nil { - icmpType = strconv.Itoa(typeCode.Type) - if typeCode.Code != nil { - icmpCode = strconv.Itoa(*typeCode.Code) - } - } - return fmt.Sprintf("Type: %v, Code: %v", icmpType, icmpCode) -} - -func printProtocolName(protocol netp.Protocol) string { - switch p := protocol.(type) { - case netp.ICMP: - return "ICMP" - case netp.TCPUDP: - return strings.ToUpper(string(p.ProtocolString())) - case netp.AnyProtocol: - return anyProtocol - } - return "" -} diff --git a/pkg/io/mdio/sg.go b/pkg/io/mdio/sg.go deleted file mode 100644 index 3277b3fa..00000000 --- a/pkg/io/mdio/sg.go +++ /dev/null @@ -1,140 +0,0 @@ -/* -Copyright 2023- IBM Inc. All Rights Reserved. -SPDX-License-Identifier: Apache-2.0 -*/ - -package mdio - -import ( - "errors" - "fmt" - - "github.com/np-guard/models/pkg/interval" - "github.com/np-guard/models/pkg/netp" - "github.com/np-guard/models/pkg/netset" - - "github.com/np-guard/vpc-network-config-synthesis/pkg/ir" -) - -func (w *Writer) WriteSG(collection *ir.SGCollection, vpc string) error { - if err := w.writeAll(sgHeader()); err != nil { - return err - } - for _, sgName := range collection.SortedSGNames(vpc) { - vpcName := ir.VpcFromScopedResource(string(sgName)) - sgTable, err := makeSGTable(collection.SGs[vpcName][sgName], sgName) - if err != nil { - return err - } - if err := w.writeAll(sgTable); err != nil { - return err - } - } - return nil -} - -func sgHeader() [][]string { - return [][]string{{ - "", - "SG", - "Direction", - "Remote type", - "Remote", - "Protocol", - "Protocol params", - "Description", - "", - }, { - "", - leftAlign, - leftAlign, - leftAlign, - leftAlign, - leftAlign, - leftAlign, - leftAlign, - "", - }} -} - -func makeSGRow(rule *ir.SGRule, sgName ir.SGName) ([]string, error) { - remoteType, err1 := sgRemoteType(rule.Remote) - remote, err2 := sgRemote(rule.Remote) - protocolParams, err3 := printProtocolParams(rule.Protocol) - if err := errors.Join(err1, err2, err3); err != nil { - return nil, err - } - - return []string{ - "", - string(sgName), - direction(rule.Direction), - remoteType, - remote, - printProtocolName(rule.Protocol), - protocolParams, - rule.Explanation, - "", - }, nil -} - -func makeSGTable(t *ir.SG, sgName ir.SGName) ([][]string, error) { - rules := t.AllRules() - rows := make([][]string, len(rules)) - for i, rule := range rules { - sgRow, err := makeSGRow(rule, sgName) - if err != nil { - return nil, err - } - rows[i] = sgRow - } - return rows, nil -} - -func sgPort(p interval.Interval) string { - switch { - case p.Start() == netp.MinPort && p.End() == netp.MaxPort: - return "any port" - default: - return fmt.Sprintf("ports %v-%v", p.Start(), p.End()) - } -} - -func sgRemoteType(t ir.RemoteType) (string, error) { - switch r := t.(type) { - case *netset.IPBlock: - if ipString := r.ToIPAddressString(); ipString != "" { // single IP address - return "IP address", nil - } - return "CIDR block", nil - case ir.SGName: - return "Security group", nil - } - return "", fmt.Errorf("impossible remote type %T", t) -} - -func sgRemote(r ir.RemoteType) (string, error) { - switch tr := r.(type) { - case *netset.IPBlock: - s := tr.String() - if s == netset.CidrAll { - return "Any IP", nil - } - return s, nil - case ir.SGName: - return tr.String(), nil - } - return "", fmt.Errorf("impossible remote %v (%T)", r, r) -} - -func printProtocolParams(protocol netp.Protocol) (string, error) { - switch p := protocol.(type) { - case netp.ICMP: - return printICMPTypeCode(protocol), nil - case netp.TCPUDP: - return sgPort(p.DstPorts()), nil - case netp.AnyProtocol: - return "", nil - } - return "", fmt.Errorf("impossible protocol %v (type %T)", protocol, protocol) -} diff --git a/pkg/io/tfio/acl.go b/pkg/io/tfio/acl.go index b0dd23e8..a60380a2 100644 --- a/pkg/io/tfio/acl.go +++ b/pkg/io/tfio/acl.go @@ -11,14 +11,13 @@ import ( "strings" "github.com/np-guard/models/pkg/netp" - "github.com/np-guard/models/pkg/netset" "github.com/np-guard/vpc-network-config-synthesis/pkg/io/tfio/tf" "github.com/np-guard/vpc-network-config-synthesis/pkg/ir" ) // WriteACL prints an entire collection of acls as a sequence of terraform resources. -func (w *Writer) WriteACL(c *ir.ACLCollection, vpc string) error { +func (w *Writer) WriteACL(c *ir.ACLCollection, vpc string, _ bool) error { collection, err := aclCollection(c, vpc) if err != nil { return err @@ -28,8 +27,7 @@ func (w *Writer) WriteACL(c *ir.ACLCollection, vpc string) error { if err != nil { return err } - err = w.w.Flush() - return err + return w.w.Flush() } func aclProtocol(t netp.Protocol) []tf.Block { @@ -64,15 +62,21 @@ func aclRule(rule *ir.ACLRule, name string) (tf.Block, error) { {Name: "source", Value: quote(rule.Source.String())}, {Name: "destination", Value: quote(rule.Destination.String())}, } + + comment := "\n" + if rule.Explanation != "" { + comment = fmt.Sprintf("# %v", rule.Explanation) + } + return tf.Block{Name: "rules", - Comment: fmt.Sprintf("# %v", rule.Explanation), + Comment: comment, Arguments: arguments, Blocks: aclProtocol(rule.Protocol), }, nil } -func singleACL(t *ir.ACL, comment string) (tf.Block, error) { - rules := t.Rules() +func singleACL(acl *ir.ACL, vpcName string) (tf.Block, error) { + rules := acl.Rules() blocks := make([]tf.Block, len(rules)) for i, rule := range rules { rule, err := aclRule(rule, fmt.Sprintf("rule%v", i)) @@ -81,49 +85,46 @@ func singleACL(t *ir.ACL, comment string) (tf.Block, error) { } blocks[i] = rule } - aclName := ir.ChangeScoping(t.Name()) + aclName := ir.ChangeScoping(acl.Name()) if err := verifyName(aclName); err != nil { return tf.Block{}, err } return tf.Block{ - Comment: comment, + Comment: aclComment(acl.Subnets), Name: "resource", Labels: []string{quote("ibm_is_network_acl"), quote(aclName)}, Arguments: []tf.Argument{ {Name: "name", Value: quote(aclName)}, //nolint:revive // obvious false positive {Name: "resource_group", Value: "local.acl_synth_resource_group_id"}, - {Name: "vpc", Value: fmt.Sprintf("local.acl_synth_%s_id", ir.VpcFromScopedResource(t.Subnet))}, + {Name: "vpc", Value: fmt.Sprintf("local.acl_synth_%s_id", vpcName)}, }, Blocks: blocks, }, nil } -func aclCollection(t *ir.ACLCollection, vpc string) (*tf.ConfigFile, error) { - sortedACLs := t.SortedACLSubnets(vpc) - var acls = make([]tf.Block, len(sortedACLs)) - i := 0 - for _, subnet := range sortedACLs { - comment := "" - vpcName := ir.VpcFromScopedResource(subnet) - acl := t.ACLs[vpcName][subnet] - if len(sortedACLs) > 1 { // not a single nacl - comment = fmt.Sprintf("\n# %v [%v]", subnet, subnetCidr(acl)) +func aclCollection(collection *ir.ACLCollection, vpc string) (*tf.ConfigFile, error) { + res := make([]tf.Block, 0) + for _, vpcName := range collection.VpcNames() { + if vpc != vpcName && vpc != "" { + continue } - singleACL, err := singleACL(acl, comment) - if err != nil { - return nil, err + for _, aclName := range collection.SortedACLNames(vpcName) { + acl := collection.ACLs[vpcName][aclName] + aclBlock, err := singleACL(acl, vpcName) + if err != nil { + return nil, err + } + res = append(res, aclBlock) } - acls[i] = singleACL - i += 1 } return &tf.ConfigFile{ - Resources: acls, + Resources: res, }, nil } -func subnetCidr(acl *ir.ACL) *netset.IPBlock { - if len(acl.Internal) > 0 { - return acl.Internal[0].Target() +func aclComment(subnets []string) string { + if len(subnets) == 0 { + return "# No attached subnets\n" } - return acl.External[0].Target() + return fmt.Sprintf("# Attached subnets: %s\n", strings.Join(subnets, ", ")) } diff --git a/pkg/io/tfio/sg.go b/pkg/io/tfio/sg.go index 747be97d..05d330a1 100644 --- a/pkg/io/tfio/sg.go +++ b/pkg/io/tfio/sg.go @@ -18,7 +18,7 @@ import ( ) // WriteSG prints an entire collection of Security Groups as a sequence of terraform resources. -func (w *Writer) WriteSG(c *ir.SGCollection, vpc string) error { +func (w *Writer) WriteSG(c *ir.SGCollection, vpc string, _ bool) error { collection, err := sgCollection(c, vpc) if err != nil { return err @@ -72,10 +72,15 @@ func sgRule(rule *ir.SGRule, sgName ir.SGName, i int) (tf.Block, error) { return tf.Block{}, err } + comment := "" + if rule.Explanation != "" { + comment = fmt.Sprintf("# %v", rule.Explanation) + } + return tf.Block{ Name: "resource", - Labels: []string{quote("ibm_is_security_group_rule"), ir.ChangeScoping(quote(ruleName))}, - Comment: fmt.Sprintf("# %v", rule.Explanation), + Labels: []string{quote("ibm_is_security_group_rule"), quote(ruleName)}, + Comment: comment, Arguments: []tf.Argument{ {Name: "group", Value: group}, {Name: "direction", Value: quote(direction(rule.Direction))}, @@ -85,15 +90,18 @@ func sgRule(rule *ir.SGRule, sgName ir.SGName, i int) (tf.Block, error) { }, nil } -func sg(sgName, comment string) (tf.Block, error) { - vpcName := ir.VpcFromScopedResource(sgName) - sgName = ir.ChangeScoping(sgName) +func sg(sG *ir.SG, vpcName string) (tf.Block, error) { + sgName := ir.ChangeScoping(sG.SGName.String()) + comment := fmt.Sprintf("\n### SG %s is attached to %s", sgName, strings.Join(sG.Targets, ", ")) + if len(sG.Targets) == 0 { + comment = fmt.Sprintf("\n### SG %s is not attached to anything", sgName) + } if err := verifyName(sgName); err != nil { return tf.Block{}, err } return tf.Block{ Name: "resource", //nolint:revive // obvious false positive - Labels: []string{quote("ibm_is_security_group"), ir.ChangeScoping(quote(sgName))}, + Labels: []string{quote("ibm_is_security_group"), quote(sgName)}, Comment: comment, Arguments: []tf.Argument{ {Name: "name", Value: quote("sg-" + sgName)}, @@ -103,24 +111,27 @@ func sg(sgName, comment string) (tf.Block, error) { }, nil } -func sgCollection(t *ir.SGCollection, vpc string) (*tf.ConfigFile, error) { - var resources []tf.Block //nolint:prealloc // nontrivial to calculate, and an unlikely performance bottleneck - for _, sgName := range t.SortedSGNames(vpc) { - comment := "" - vpcName := ir.VpcFromScopedResource(string(sgName)) - rules := t.SGs[vpcName][sgName].AllRules() - comment = fmt.Sprintf("\n### SG attached to %v", sgName) - sg, err := sg(sgName.String(), comment) - if err != nil { - return nil, err +func sgCollection(collection *ir.SGCollection, vpc string) (*tf.ConfigFile, error) { + var resources []tf.Block + + for _, vpcName := range collection.VpcNames() { + if vpc != vpcName && vpc != "" { + continue } - resources = append(resources, sg) - for i, rule := range rules { - rule, err := sgRule(rule, sgName, i) + for _, sgName := range collection.SortedSGNames(vpcName) { + sG := collection.SGs[vpcName][sgName] + sg, err := sg(sG, vpcName) if err != nil { return nil, err } - resources = append(resources, rule) + resources = append(resources, sg) + for i, rule := range sG.AllRules() { + rule, err := sgRule(rule, sgName, i) + if err != nil { + return nil, err + } + resources = append(resources, rule) + } } } return &tf.ConfigFile{ diff --git a/pkg/ir/acl.go b/pkg/ir/acl.go index b1de36c3..ccc46c81 100644 --- a/pkg/ir/acl.go +++ b/pkg/ir/acl.go @@ -15,36 +15,41 @@ import ( "github.com/np-guard/vpc-network-config-synthesis/pkg/utils" ) -type Action string +type ( + Action string + + ACLRule struct { + Action Action + Direction Direction + Source *netset.IPBlock + Destination *netset.IPBlock + Protocol netp.Protocol + Explanation string + } + + ACL struct { + ACLName string + Subnets []string + Internal []*ACLRule + External []*ACLRule + Inbound []*ACLRule + Outbound []*ACLRule + } + + ACLCollection struct { + ACLs map[ID]map[string]*ACL + } + + ACLWriter interface { + WriteACL(aclColl *ACLCollection, vpc string, isSynth bool) error + } +) const ( Allow Action = "allow" Deny Action = "deny" ) -type ACLRule struct { - Action Action - Direction Direction - Source *netset.IPBlock - Destination *netset.IPBlock - Protocol netp.Protocol - Explanation string -} - -type ACL struct { - Subnet string - Internal []*ACLRule - External []*ACLRule -} - -type ACLCollection struct { - ACLs map[ID]map[string]*ACL -} - -type ACLWriter interface { - WriteACL(aclColl *ACLCollection, vpc string) error -} - func (r *ACLRule) isRedundant(rules []*ACLRule) bool { for _, rule := range rules { if rule.mustSupersede(r) { @@ -70,10 +75,12 @@ func (r *ACLRule) Target() *netset.IPBlock { } func (a *ACL) Rules() []*ACLRule { + if a.Internal == nil { // optimization mode + return append(a.Inbound, a.Outbound...) + } rules := a.Internal if len(a.External) != 0 { - rules = append(rules, makeDenyInternal()...) - rules = append(rules, a.External...) + rules = append(rules, append(makeDenyInternal(), a.External...)...) } return rules } @@ -88,7 +95,7 @@ func (a *ACL) AppendInternal(rule *ACLRule) { } func (a *ACL) Name() string { - return fmt.Sprintf("acl-%v", a.Subnet) + return fmt.Sprintf("acl-%v", a.ACLName) } func (a *ACL) AppendExternal(rule *ACLRule) { @@ -105,29 +112,32 @@ func NewACLCollection() *ACLCollection { return &ACLCollection{ACLs: map[ID]map[string]*ACL{}} } -func NewACL() *ACL { - return &ACL{Internal: []*ACLRule{}, External: []*ACLRule{}} +func NewACL(subnet string) *ACL { + return &ACL{ACLName: subnet, Subnets: []string{subnet}, Internal: []*ACLRule{}, External: []*ACLRule{}} } -func (c *ACLCollection) LookupOrCreate(name string) *ACL { - vpcName := VpcFromScopedResource(name) - if acl, ok := c.ACLs[vpcName][name]; ok { +func (c *ACLCollection) LookupOrCreate(subnet string) *ACL { + vpcName := VpcFromScopedResource(subnet) + if acl, ok := c.ACLs[vpcName][subnet]; ok { return acl } - newACL := NewACL() - newACL.Subnet = name + newACL := NewACL(subnet) if c.ACLs[vpcName] == nil { c.ACLs[vpcName] = make(map[string]*ACL) } - c.ACLs[vpcName][name] = newACL + c.ACLs[vpcName][subnet] = newACL return newACL } -func (c *ACLCollection) Write(w Writer, vpc string) error { - return w.WriteACL(c, vpc) +func (c *ACLCollection) VpcNames() []string { + return utils.SortedMapKeys(c.ACLs) +} + +func (c *ACLCollection) Write(w Writer, vpc string, isSynth bool) error { + return w.WriteACL(c, vpc, isSynth) } -func (c *ACLCollection) SortedACLSubnets(vpc string) []string { +func (c *ACLCollection) SortedACLNames(vpc string) []string { if vpc == "" { return utils.SortedAllInnerMapsKeys(c.ACLs) } diff --git a/pkg/ir/common.go b/pkg/ir/common.go index e10b1265..49d87bbc 100644 --- a/pkg/ir/common.go +++ b/pkg/ir/common.go @@ -5,18 +5,21 @@ SPDX-License-Identifier: Apache-2.0 package ir -type Direction string +type ( + Direction string + + Collection interface { + Write(writer Writer, vpc string, isSynth bool) error + VpcNames() []string + } + + Writer interface { + ACLWriter + SGWriter + } +) const ( Outbound Direction = "outbound" Inbound Direction = "inbound" ) - -type Writer interface { - ACLWriter - SGWriter -} - -type Collection interface { - Write(writer Writer, vpc string) error -} diff --git a/pkg/ir/sg.go b/pkg/ir/sg.go index 0011b011..3a1957c3 100644 --- a/pkg/ir/sg.go +++ b/pkg/ir/sg.go @@ -10,6 +10,7 @@ import ( "reflect" "github.com/np-guard/models/pkg/netp" + "github.com/np-guard/models/pkg/netset" "github.com/np-guard/vpc-network-config-synthesis/pkg/utils" ) @@ -25,36 +26,40 @@ const ( SGResourceFileShareMountTarget SGResource = "fsmt" ) -type SGName string +type ( + SGName string -func (s SGName) String() string { - return string(s) -} + RemoteType interface { + fmt.Stringer + // *netset.IPBlock | SGName + } -type RemoteType interface { - fmt.Stringer - // *netset.IPBlock | SGName -} + SGRule struct { + Direction Direction + Remote RemoteType + Protocol netp.Protocol + Local *netset.IPBlock + Explanation string + } -type SGRule struct { - Direction Direction - Remote RemoteType - Protocol netp.Protocol - Explanation string -} + SG struct { + SGName SGName + InboundRules map[string][]*SGRule // the key is the locals value + OutboundRules map[string][]*SGRule // the key is the locals value + Targets []ID + } -type SG struct { - InboundRules []*SGRule - OutboundRules []*SGRule - Attached []ID -} + SGCollection struct { + SGs map[ID]map[SGName]*SG + } -type SGCollection struct { - SGs map[ID]map[SGName]*SG -} + SGWriter interface { + WriteSG(sgColl *SGCollection, vpc string, isSynth bool) error + } +) -type SGWriter interface { - WriteSG(sgColl *SGCollection, vpc string) error +func (s SGName) String() string { + return string(s) } func (r *SGRule) isRedundant(rules []*SGRule) bool { @@ -74,8 +79,17 @@ func (r *SGRule) mustSupersede(other *SGRule) bool { return res } -func NewSG() *SG { - return &SG{InboundRules: []*SGRule{}, OutboundRules: []*SGRule{}, Attached: []ID{}} +func NewSGRule(direction Direction, remote RemoteType, p netp.Protocol, local *netset.IPBlock, e string) *SGRule { + return &SGRule{Direction: direction, Remote: remote, Protocol: p, + Local: local, Explanation: e} +} + +func NewSG(sgName SGName) *SG { + return &SG{SGName: sgName, + InboundRules: make(map[string][]*SGRule), + OutboundRules: make(map[string][]*SGRule), + Targets: []ID{}, + } } func NewSGCollection() *SGCollection { @@ -87,7 +101,7 @@ func (c *SGCollection) LookupOrCreate(name SGName) *SG { if sg, ok := c.SGs[vpcName][name]; ok { return sg } - newSG := NewSG() + newSG := NewSG(name) if c.SGs[vpcName] == nil { c.SGs[vpcName] = make(map[SGName]*SG) } @@ -96,20 +110,33 @@ func (c *SGCollection) LookupOrCreate(name SGName) *SG { } func (a *SG) Add(rule *SGRule) { - if rule.Direction == Outbound && !rule.isRedundant(a.OutboundRules) { - a.OutboundRules = append(a.OutboundRules, rule) + local := rule.Local.String() + if rule.Direction == Outbound && !rule.isRedundant(a.OutboundRules[local]) { + a.OutboundRules[local] = append(a.OutboundRules[local], rule) } - if rule.Direction == Inbound && !rule.isRedundant(a.InboundRules) { - a.InboundRules = append(a.InboundRules, rule) + + if rule.Direction == Inbound && !rule.isRedundant(a.InboundRules[local]) { + a.InboundRules[local] = append(a.InboundRules[local], rule) } } func (a *SG) AllRules() []*SGRule { - return append(a.InboundRules, a.OutboundRules...) + res := make([]*SGRule, 0) + for _, key := range utils.SortedMapKeys(a.InboundRules) { + res = append(res, a.InboundRules[key]...) + } + for _, key := range utils.SortedMapKeys(a.OutboundRules) { + res = append(res, a.OutboundRules[key]...) + } + return res +} + +func (c *SGCollection) VpcNames() []string { + return utils.SortedMapKeys(c.SGs) } -func (c *SGCollection) Write(w Writer, vpc string) error { - return w.WriteSG(c, vpc) +func (c *SGCollection) Write(w Writer, vpc string, isSynth bool) error { + return w.WriteSG(c, vpc, isSynth) } func (c *SGCollection) SortedSGNames(vpc ID) []SGName { diff --git a/pkg/optimize/acl/acl.go b/pkg/optimize/acl/acl.go new file mode 100644 index 00000000..33fcbba2 --- /dev/null +++ b/pkg/optimize/acl/acl.go @@ -0,0 +1,31 @@ +/* +Copyright 2023- IBM Inc. All Rights Reserved. +SPDX-License-Identifier: Apache-2.0 +*/ + +package acloptimizer + +import ( + "github.com/np-guard/vpc-network-config-synthesis/pkg/ir" + "github.com/np-guard/vpc-network-config-synthesis/pkg/optimize" +) + +type ( + aclOptimizer struct { + aclCollection *ir.ACLCollection + aclName string + aclVPC *string + } +) + +func NewACLOptimizer(collection ir.Collection, aclName string) optimize.Optimizer { + components := ir.ScopingComponents(aclName) + if len(components) == 1 { + return &aclOptimizer{aclCollection: collection.(*ir.ACLCollection), aclName: aclName, aclVPC: nil} + } + return &aclOptimizer{aclCollection: collection.(*ir.ACLCollection), aclName: components[1], aclVPC: &components[0]} +} + +func (a *aclOptimizer) Optimize() (ir.Collection, error) { + return nil, nil +} diff --git a/pkg/optimize/common.go b/pkg/optimize/common.go new file mode 100644 index 00000000..9d62a104 --- /dev/null +++ b/pkg/optimize/common.go @@ -0,0 +1,80 @@ +/* +Copyright 2023- IBM Inc. All Rights Reserved. +SPDX-License-Identifier: Apache-2.0 +*/ + +package optimize + +import ( + "sort" + + "github.com/np-guard/models/pkg/ds" + "github.com/np-guard/models/pkg/netp" + "github.com/np-guard/models/pkg/netset" + + "github.com/np-guard/vpc-network-config-synthesis/pkg/ir" +) + +type Optimizer interface { + // attempts to reduce number of SG/nACL rules + Optimize() (ir.Collection, error) +} + +// each IPBlock is a single CIDR. The CIDRs are disjoint. +func SortPartitionsByIPAddrs[T any](p []ds.Pair[*netset.IPBlock, T]) []ds.Pair[*netset.IPBlock, T] { + cmp := func(i, j int) bool { + if p[i].Left.FirstIPAddress() == p[j].Left.FirstIPAddress() { + return p[i].Left.LastIPAddress() < p[j].Left.LastIPAddress() + } + return p[i].Left.FirstIPAddress() < p[j].Left.FirstIPAddress() + } + sort.Slice(p, cmp) + return p +} + +// returns true if this 0 && !continuation(cubes[i-1], cubes[i], allCubes) { + result = append(result, createActiveRules(activeRules, cubes[i-1].Left.LastIPAddressObject(), direction, l)...) + activeRules = make(map[*netset.IPBlock]netp.Protocol) + } + + // if the proctol is not contained in the current cube, we will generate SG rules + // calculate active ports = active rules covers these ports + activePorts := interval.NewCanonicalSet() + for ipb, protocol := range activeRules { + if tcpudp, ok := protocol.(netp.TCPUDP); ok { + if !tcpudp.DstPorts().ToSet().IsSubset(cubes[i].Right) { + result = append(result, createNewRules(protocol, ipb, cubes[i-1].Left.LastIPAddressObject(), direction, l)...) + } else { + activePorts.AddInterval(tcpudp.DstPorts()) + } + } + } + + // if the cube contains ports that are not contained in the active rules, new rules will be created + for _, ports := range cubes[i].Right.Intervals() { + if !ports.ToSet().IsSubset(activePorts) { + p, _ := netp.NewTCPUDP(isTCP, netp.MinPort, netp.MaxPort, int(ports.Start()), int(ports.End())) + activeRules[cubes[i].Left.FirstIPAddressObject()] = p + } + } + } + // generate all the existing rules + return append(result, createActiveRules(activeRules, cubes[len(cubes)-1].Left.LastIPAddressObject(), direction, l)...) +} + +// icmpIPCubesToRules converts cubes representing icmp protocol rules to SG rules +func icmpIPCubesToRules(cubes []ds.Pair[*netset.IPBlock, *netset.ICMPSet], allCubes *netset.IPBlock, direction ir.Direction, + l *netset.IPBlock) []*ir.SGRule { + if len(cubes) == 0 { + return []*ir.SGRule{} + } + + activeRules := make(map[*netset.IPBlock]netp.Protocol) // the key is the first IP + result := make([]*ir.SGRule, 0) + + for i := range cubes { + // if it is not possible to continue the rule between the cubes, generate all the existing rules + if i > 0 && !continuation(cubes[i-1], cubes[i], allCubes) { + result = append(result, createActiveRules(activeRules, cubes[i-1].Left.LastIPAddressObject(), direction, l)...) + activeRules = make(map[*netset.IPBlock]netp.Protocol) + } + + // if the proctol is not contained in the current cube, we will generate SG rules + // calculate activeICMP = active rules covers these icmp values + activeICMP := netset.EmptyICMPSet() + for ipb, protocol := range activeRules { + if icmp, ok := protocol.(netp.ICMP); ok { + ruleIcmpSet := optimize.IcmpRuleToIcmpSet(icmp) + if !ruleIcmpSet.IsSubset(cubes[i].Right) { + result = append(result, createNewRules(protocol, ipb, cubes[i-1].Left.LastIPAddressObject(), direction, l)...) + } else { + activeICMP.Union(ruleIcmpSet) + } + } + } + + // if the cube contains icmp values that are not contained in the active rules, new rules will be created + for _, p := range optimize.IcmpsetPartitions(cubes[i].Right) { + if !optimize.IcmpRuleToIcmpSet(p).IsSubset(activeICMP) { + activeRules[cubes[i].Left.FirstIPAddressObject()] = p + } + } + } + + // generate all the existing rules + return append(result, createActiveRules(activeRules, cubes[len(cubes)-1].Left.LastIPAddressObject(), direction, l)...) +} + +// continuation returns true if the rules can be continued between the two cubes +func continuation[T ds.Set[T]](prevPair, currPair ds.Pair[*netset.IPBlock, T], allProtocolCubes *netset.IPBlock) bool { + prevIPBlock := prevPair.Left + currIPBlock := currPair.Left + touching, _ := prevIPBlock.TouchingIPRanges(currIPBlock) + if touching { + return true + } + startH, _ := prevIPBlock.NextIP() + endH, _ := currIPBlock.PreviousIP() + hole, _ := netset.IPBlockFromIPRange(startH, endH) + return hole.IsSubset(allProtocolCubes) +} + +// creates sgRules from SG active rules +func createActiveRules(activeRules map[*netset.IPBlock]netp.Protocol, endIP *netset.IPBlock, direction ir.Direction, + l *netset.IPBlock) []*ir.SGRule { + res := make([]*ir.SGRule, 0) + for ipb, protocol := range activeRules { + res = append(res, createNewRules(protocol, ipb, endIP, direction, l)...) + } + return res +} + +// createNewRules breaks the startIP-endIP ip range into cidrs and creates SG rules +func createNewRules(protocol netp.Protocol, startIP, endIP *netset.IPBlock, direction ir.Direction, l *netset.IPBlock) []*ir.SGRule { + res := make([]*ir.SGRule, 0) + ipRange, _ := netset.IPBlockFromIPRange(startIP, endIP) + for _, cidr := range ipRange.SplitToCidrs() { + res = append(res, ir.NewSGRule(direction, cidr, protocol, l, "")) + } + return res +} diff --git a/pkg/optimize/sg/reduceCubes.go b/pkg/optimize/sg/reduceCubes.go new file mode 100644 index 00000000..44d9a9d7 --- /dev/null +++ b/pkg/optimize/sg/reduceCubes.go @@ -0,0 +1,130 @@ +/* +Copyright 2023- IBM Inc. All Rights Reserved. +SPDX-License-Identifier: Apache-2.0 +*/ + +package sgoptimizer + +import ( + "slices" + + "github.com/np-guard/models/pkg/netset" + + "github.com/np-guard/vpc-network-config-synthesis/pkg/optimize" +) + +func reduceSGCubes(spans *sgCubesPerProtocol) { + deleteOtherProtocolIfAllProtocolExists(spans) + compressThreeProtocolsToAllProtocol(spans) +} + +// delete other protocols rules if all protocol rule exists +func deleteOtherProtocolIfAllProtocolExists(spans *sgCubesPerProtocol) { + for _, sgName := range spans.all { + delete(spans.tcp, sgName) + delete(spans.udp, sgName) + delete(spans.icmp, sgName) + } +} + +// merge tcp, udp and icmp rules into all protocol rule +func compressThreeProtocolsToAllProtocol(spans *sgCubesPerProtocol) { + for sgName, tcpPorts := range spans.tcp { + if udpPorts, ok := spans.udp[sgName]; ok { + if ic, ok := spans.icmp[sgName]; ok { + if ic.IsAll() && tcpPorts.Equal(netset.AllPorts()) && udpPorts.Equal(netset.AllPorts()) { + delete(spans.tcp, sgName) + delete(spans.udp, sgName) + delete(spans.icmp, sgName) + spans.all = append(spans.all, sgName) + } + } + } + } +} + +// observation: It pays to switch to all protocol rule when we have rules that cover all other protocols +// on exactly the same cidr (only one protocol can exceed). +// +//nolint:gocyclo // multiple if statments +func reduceIPCubes(cubes *ipCubesPerProtocol) { + tcpPtr := 0 + udpPtr := 0 + icmpPtr := 0 + + for tcpPtr < len(cubes.tcp) && udpPtr < len(cubes.udp) && icmpPtr < len(cubes.icmp) { + if !cubes.tcp[tcpPtr].Right.Equal(netset.AllPorts()) { + tcpPtr++ + continue + } + if !cubes.udp[udpPtr].Right.Equal(netset.AllPorts()) { + udpPtr++ + continue + } + if !cubes.icmp[icmpPtr].Right.IsAll() { + icmpPtr++ + continue + } + + if compressedToAllCube(cubes, tcpPtr, udpPtr, icmpPtr) { + continue + } + + tcpIP := cubes.tcp[tcpPtr].Left + udpIP := cubes.udp[udpPtr].Left + icmpIP := cubes.icmp[icmpPtr].Left + + switch { + // one protocol ipb contains two other ipbs ==> advance the smaller ipb + case udpIP.IsSubset(tcpIP) && icmpIP.IsSubset(tcpIP) && optimize.LessIPBlock(udpIP, icmpIP): + udpPtr++ + case udpIP.IsSubset(tcpIP) && icmpIP.IsSubset(tcpIP) && optimize.LessIPBlock(icmpIP, udpIP): + icmpPtr++ + case tcpIP.IsSubset(udpIP) && icmpIP.IsSubset(udpIP) && optimize.LessIPBlock(tcpIP, icmpIP): + tcpPtr++ + case tcpIP.IsSubset(udpIP) && icmpIP.IsSubset(udpIP) && optimize.LessIPBlock(icmpIP, tcpIP): + icmpPtr++ + case tcpIP.IsSubset(icmpIP) && udpIP.IsSubset(icmpIP) && optimize.LessIPBlock(tcpIP, udpIP): + tcpPtr++ + case tcpIP.IsSubset(icmpIP) && udpIP.IsSubset(icmpIP) && optimize.LessIPBlock(udpIP, tcpIP): + udpPtr++ + + // advance the smaller ipb + case optimize.LessIPBlock(tcpIP, udpIP) && optimize.LessIPBlock(tcpIP, icmpIP): + tcpPtr++ + case optimize.LessIPBlock(udpIP, tcpIP) && optimize.LessIPBlock(udpIP, icmpIP): + udpPtr++ + case optimize.LessIPBlock(icmpIP, tcpIP) && optimize.LessIPBlock(icmpIP, udpIP): + icmpPtr++ + } + } +} + +// compress three protocol rules to all protocol rule (and maybe another protocol rule) +func compressedToAllCube(cubes *ipCubesPerProtocol, tcpPtr, udpPtr, icmpPtr int) bool { + tcpIP := cubes.tcp[tcpPtr].Left + udpIP := cubes.udp[udpPtr].Left + icmpIP := cubes.icmp[icmpPtr].Left + + switch { + case udpIP.Equal(tcpIP) && udpIP.Equal(icmpIP): + cubes.tcp = slices.Delete(cubes.tcp, tcpPtr, tcpPtr+1) + fallthrough + case udpIP.IsSubset(tcpIP) && udpIP.Equal(icmpIP): + cubes.udp = slices.Delete(cubes.udp, udpPtr, udpPtr+1) + cubes.icmp = slices.Delete(cubes.icmp, icmpPtr, icmpPtr+1) + cubes.all = cubes.all.Union(udpIP) + return true + case tcpIP.IsSubset(udpIP) && tcpIP.Equal(icmpIP): + cubes.tcp = slices.Delete(cubes.tcp, tcpPtr, tcpPtr+1) + cubes.icmp = slices.Delete(cubes.icmp, icmpPtr, icmpPtr+1) + cubes.all = cubes.all.Union(tcpIP) + return true + case tcpIP.IsSubset(icmpIP) && tcpIP.Equal(udpIP): + cubes.tcp = slices.Delete(cubes.tcp, tcpPtr, tcpPtr+1) + cubes.udp = slices.Delete(cubes.udp, udpPtr, udpPtr+1) + cubes.all = cubes.all.Union(tcpIP) + return true + } + return false +} diff --git a/pkg/optimize/sg/rulesToCubes.go b/pkg/optimize/sg/rulesToCubes.go new file mode 100644 index 00000000..f3802ef1 --- /dev/null +++ b/pkg/optimize/sg/rulesToCubes.go @@ -0,0 +1,107 @@ +/* +Copyright 2023- IBM Inc. All Rights Reserved. +SPDX-License-Identifier: Apache-2.0 +*/ + +package sgoptimizer + +import ( + "github.com/np-guard/models/pkg/ds" + "github.com/np-guard/models/pkg/interval" + "github.com/np-guard/models/pkg/netp" + "github.com/np-guard/models/pkg/netset" + + "github.com/np-guard/vpc-network-config-synthesis/pkg/ir" + "github.com/np-guard/vpc-network-config-synthesis/pkg/optimize" + "github.com/np-guard/vpc-network-config-synthesis/pkg/utils" +) + +// SG remote +func rulesToSGCubes(rules *rulesPerProtocol) *sgCubesPerProtocol { + return &sgCubesPerProtocol{tcp: tcpudpRulesSGCubes(rules.tcp), + udp: tcpudpRulesSGCubes(rules.udp), + icmp: icmpRulesSGCubes(rules.icmp), + all: allProtocolRulesToSGCubes(rules.all), + } +} + +// all protocol rules to cubes +func allProtocolRulesToSGCubes(rules []*ir.SGRule) []ir.SGName { + result := make(map[ir.SGName]struct{}) + for i := range rules { + remote := rules[i].Remote.(ir.SGName) // already checked + result[remote] = struct{}{} + } + return utils.SortedMapKeys(result) +} + +// tcp/udp rules to cubes -- map where the key is the SG name and the value is the protocol ports +func tcpudpRulesSGCubes(rules []*ir.SGRule) map[ir.SGName]*netset.PortSet { + result := make(map[ir.SGName]*netset.PortSet) + for _, rule := range rules { + p := rule.Protocol.(netp.TCPUDP) // already checked + remote := rule.Remote.(ir.SGName) // already checked + if result[remote] == nil { + result[remote] = interval.NewCanonicalSet() + } + result[remote].AddInterval(p.DstPorts()) + } + return result +} + +// icmp rules to cubes -- map where the key is the SG name and the value is icmpset +func icmpRulesSGCubes(rules []*ir.SGRule) map[ir.SGName]*netset.ICMPSet { + result := make(map[ir.SGName]*netset.ICMPSet) + for _, rule := range rules { + p := rule.Protocol.(netp.ICMP) // already checked + remote := rule.Remote.(ir.SGName) // already checked + if result[remote] == nil { + result[remote] = netset.EmptyICMPSet() + } + icmpSet := optimize.IcmpRuleToIcmpSet(p) + result[remote] = result[remote].Union(icmpSet) + } + return result +} + +// IP remote +func rulesToIPCubes(rules *rulesPerProtocol) *ipCubesPerProtocol { + return &ipCubesPerProtocol{tcp: tcpudpRulesToIPCubes(rules.tcp), + udp: tcpudpRulesToIPCubes(rules.udp), + icmp: icmpRulesToIPCubes(rules.icmp), + all: allProtocolRulesToIPCubes(rules.all), + } +} + +// all protocol rules to cubes +func allProtocolRulesToIPCubes(rules []*ir.SGRule) *netset.IPBlock { + res := netset.NewIPBlock() + for i := range rules { + res = res.Union(rules[i].Remote.(*netset.IPBlock)) + } + return res +} + +// tcp/udp rules (separately) to cubes (IPBlock X portset). +func tcpudpRulesToIPCubes(rules []*ir.SGRule) []ds.Pair[*netset.IPBlock, *netset.PortSet] { + cubes := ds.NewProductLeft[*netset.IPBlock, *netset.PortSet]() + for _, rule := range rules { + ipb := rule.Remote.(*netset.IPBlock) // already checked + p := rule.Protocol.(netp.TCPUDP) // already checked + r := ds.CartesianPairLeft(ipb, p.DstPorts().ToSet()) + cubes = cubes.Union(r).(*ds.ProductLeft[*netset.IPBlock, *netset.PortSet]) + } + return optimize.SortPartitionsByIPAddrs(cubes.Partitions()) +} + +// icmp rules to cubes (IPBlock X icmp set). +func icmpRulesToIPCubes(rules []*ir.SGRule) []ds.Pair[*netset.IPBlock, *netset.ICMPSet] { + cubes := ds.NewProductLeft[*netset.IPBlock, *netset.ICMPSet]() + for _, rule := range rules { + ipb := rule.Remote.(*netset.IPBlock) // already checked + p := rule.Protocol.(netp.ICMP) // already checked + r := ds.CartesianPairLeft(ipb, optimize.IcmpRuleToIcmpSet(p)) + cubes = cubes.Union(r).(*ds.ProductLeft[*netset.IPBlock, *netset.ICMPSet]) + } + return optimize.SortPartitionsByIPAddrs(cubes.Partitions()) +} diff --git a/pkg/optimize/sg/sg.go b/pkg/optimize/sg/sg.go new file mode 100644 index 00000000..f2f443d8 --- /dev/null +++ b/pkg/optimize/sg/sg.go @@ -0,0 +1,220 @@ +/* +Copyright 2023- IBM Inc. All Rights Reserved. +SPDX-License-Identifier: Apache-2.0 +*/ + +package sgoptimizer + +import ( + "fmt" + "log" + + "github.com/np-guard/models/pkg/ds" + "github.com/np-guard/models/pkg/netp" + "github.com/np-guard/models/pkg/netset" + + "github.com/np-guard/vpc-network-config-synthesis/pkg/ir" + "github.com/np-guard/vpc-network-config-synthesis/pkg/optimize" + "github.com/np-guard/vpc-network-config-synthesis/pkg/utils" +) + +type ( + sgOptimizer struct { + sgCollection *ir.SGCollection + sgName ir.SGName + sgVPC *string + } + + ruleGroups struct { + sgRemoteRules *rulesPerProtocol + ipRemoteRules *rulesPerProtocol + } + + rulesPerProtocol struct { + tcp []*ir.SGRule + udp []*ir.SGRule + icmp []*ir.SGRule + all []*ir.SGRule + } + + sgCubesPerProtocol struct { + tcp map[ir.SGName]*netset.PortSet + udp map[ir.SGName]*netset.PortSet + icmp map[ir.SGName]*netset.ICMPSet + all []ir.SGName + } + + ipCubesPerProtocol struct { + tcp []ds.Pair[*netset.IPBlock, *netset.PortSet] + udp []ds.Pair[*netset.IPBlock, *netset.PortSet] + icmp []ds.Pair[*netset.IPBlock, *netset.ICMPSet] + all *netset.IPBlock + } +) + +func NewSGOptimizer(collection ir.Collection, sgName string) optimize.Optimizer { + components := ir.ScopingComponents(sgName) + if len(components) == 1 { + return &sgOptimizer{sgCollection: collection.(*ir.SGCollection), sgName: ir.SGName(sgName), sgVPC: nil} + } + return &sgOptimizer{sgCollection: collection.(*ir.SGCollection), sgName: ir.SGName(components[1]), sgVPC: &components[0]} +} + +// Optimize attempts to reduce the number of SG rules +// if -n was supplied, it will attempt to reduce the number of rules only in the requested SG +// otherwise, it will attempt to reduce the number of rules in all SGs +func (s *sgOptimizer) Optimize() (ir.Collection, error) { + if s.sgName != "" { + for _, vpcName := range utils.SortedMapKeys(s.sgCollection.SGs) { + if _, ok := s.sgCollection.SGs[vpcName][s.sgName]; ok { + s.optimizeSG(vpcName, s.sgName) + return s.sgCollection, nil + } + } + return nil, fmt.Errorf("could no find %s sg", s.sgName) + } + + for _, vpcName := range utils.SortedMapKeys(s.sgCollection.SGs) { + for _, sgName := range utils.SortedMapKeys(s.sgCollection.SGs[vpcName]) { + s.optimizeSG(vpcName, sgName) + } + } + return s.sgCollection, nil +} + +// optimizeSG attempts to reduce the number of SG rules +// the algorithm attempts to reduce both inbound and outbound rules separately +// A message is printed to the log at the end of the algorithm +func (s *sgOptimizer) optimizeSG(vpcName string, sgName ir.SGName) { + sg := s.sgCollection.SGs[vpcName][sgName] + reducedRules := 0 + + // reduce inbound rules first + for l, rules := range sg.InboundRules { + local, _ := netset.IPBlockFromCidr(l) + newInboundRules := s.reduceRules(rules, ir.Inbound, local) + if len(rules) > len(newInboundRules) { + reducedRules += len(rules) - len(newInboundRules) + sg.InboundRules[l] = newInboundRules + } + } + + // reduce outbound rules second + for l, rules := range sg.OutboundRules { + local, _ := netset.IPBlockFromCidr(l) + newOutboundRules := s.reduceRules(rules, ir.Outbound, local) + if len(rules) > len(newOutboundRules) { + reducedRules += len(rules) - len(newOutboundRules) + sg.OutboundRules[l] = newOutboundRules + } + } + + // print a message to the log + switch { + case reducedRules == 0: + log.Printf("no rules were reduced in sg %s\n", string(sgName)) + case reducedRules == 1: + log.Printf("1 rule was reduced in sg %s\n", string(sgName)) + default: + log.Printf("%d rules were reduced in sg %s\n", reducedRules, string(sgName)) + } +} + +// reduceSGRules attempts to reduce the number of rules with different remote types separately +func (s *sgOptimizer) reduceRules(rules []*ir.SGRule, direction ir.Direction, l *netset.IPBlock) []*ir.SGRule { + // separate all rules to groups of protocol X remote ([tcp, udp, icmp, protocolAll] X [ip, sg]) + ruleGroups := divideSGRules(rules) + + // rules with SG as a remote + optimizedRulesToSG := reduceRulesSGRemote(rulesToSGCubes(ruleGroups.sgRemoteRules), direction, l) + originlRulesToSG := ruleGroups.sgRemoteRules.allRules() + if len(originlRulesToSG) < len(optimizedRulesToSG) { // failed to reduce number of rules + optimizedRulesToSG = originlRulesToSG + } + + // rules with IPBlock as a remote + optimizedRulesToIPAddrs := reduceRulesIPRemote(rulesToIPCubes(ruleGroups.ipRemoteRules), direction, l) + originalRulesToIPAddrs := ruleGroups.ipRemoteRules.allRules() + if len(originalRulesToIPAddrs) < len(optimizedRulesToSG) { // failed to reduce number of rules + optimizedRulesToIPAddrs = originalRulesToIPAddrs + } + + return append(optimizedRulesToSG, optimizedRulesToIPAddrs...) +} + +func reduceRulesSGRemote(cubes *sgCubesPerProtocol, direction ir.Direction, l *netset.IPBlock) []*ir.SGRule { + reduceSGCubes(cubes) + + // cubes to SG rules + tcpRules := tcpudpSGCubesToRules(cubes.tcp, direction, true, l) + udpRules := tcpudpSGCubesToRules(cubes.udp, direction, false, l) + icmpRules := icmpSGCubesToRules(cubes.icmp, direction, l) + allRules := protocolAllCubesToRules(cubes.all, direction, l) + + // return all rules + return append(tcpRules, append(udpRules, append(icmpRules, allRules...)...)...) +} + +func reduceRulesIPRemote(cubes *ipCubesPerProtocol, direction ir.Direction, l *netset.IPBlock) []*ir.SGRule { + reduceIPCubes(cubes) + + // cubes to SG rules + tcpRules := tcpudpIPCubesToRules(cubes.tcp, cubes.all, direction, true, l) + udpRules := tcpudpIPCubesToRules(cubes.udp, cubes.all, direction, false, l) + icmpRules := icmpIPCubesToRules(cubes.icmp, cubes.all, direction, l) + allRules := allProtocolIPCubesIPToRules(cubes.all, direction, l) + + // return all rules + return append(tcpRules, append(udpRules, append(icmpRules, allRules...)...)...) +} + +// divide SGCollection to TCP/UDP/ICMP/ProtocolALL X SGRemote/IPAddrs rules +func divideSGRules(rules []*ir.SGRule) *ruleGroups { + rulesToSG := &rulesPerProtocol{tcp: make([]*ir.SGRule, 0), udp: make([]*ir.SGRule, 0), + icmp: make([]*ir.SGRule, 0), all: make([]*ir.SGRule, 0)} + rulesToIPAddrs := &rulesPerProtocol{tcp: make([]*ir.SGRule, 0), udp: make([]*ir.SGRule, 0), + icmp: make([]*ir.SGRule, 0), all: make([]*ir.SGRule, 0)} + + for _, rule := range rules { + // TCP rule + if p, ok := rule.Protocol.(netp.TCPUDP); ok && p.ProtocolString() == "TCP" { + if _, ok := rule.Remote.(*netset.IPBlock); ok { + rulesToIPAddrs.tcp = append(rulesToIPAddrs.tcp, rule) + } else { + rulesToSG.tcp = append(rulesToSG.tcp, rule) + } + } + + // UDP rule + if p, ok := rule.Protocol.(netp.TCPUDP); ok && p.ProtocolString() == "UDP" { + if _, ok := rule.Remote.(*netset.IPBlock); ok { + rulesToIPAddrs.udp = append(rulesToIPAddrs.udp, rule) + } else { + rulesToSG.udp = append(rulesToSG.udp, rule) + } + } + + // ICMP rule + if _, ok := rule.Protocol.(netp.ICMP); ok { + if _, ok := rule.Remote.(*netset.IPBlock); ok { + rulesToIPAddrs.icmp = append(rulesToIPAddrs.icmp, rule) + } else { + rulesToSG.icmp = append(rulesToSG.icmp, rule) + } + } + + // all protocol rules + if _, ok := rule.Protocol.(netp.AnyProtocol); ok { + if _, ok := rule.Remote.(*netset.IPBlock); ok { + rulesToIPAddrs.all = append(rulesToIPAddrs.all, rule) + } else { + rulesToSG.all = append(rulesToSG.all, rule) + } + } + } + return &ruleGroups{sgRemoteRules: rulesToSG, ipRemoteRules: rulesToIPAddrs} +} + +func (s *rulesPerProtocol) allRules() []*ir.SGRule { + return append(s.tcp, append(s.udp, append(s.icmp, s.all...)...)...) +} diff --git a/pkg/optimize/sg/sgCubesToRules.go b/pkg/optimize/sg/sgCubesToRules.go new file mode 100644 index 00000000..03698f78 --- /dev/null +++ b/pkg/optimize/sg/sgCubesToRules.go @@ -0,0 +1,46 @@ +/* +Copyright 2023- IBM Inc. All Rights Reserved. +SPDX-License-Identifier: Apache-2.0 +*/ + +package sgoptimizer + +import ( + "github.com/np-guard/models/pkg/netp" + "github.com/np-guard/models/pkg/netset" + + "github.com/np-guard/vpc-network-config-synthesis/pkg/ir" + "github.com/np-guard/vpc-network-config-synthesis/pkg/optimize" +) + +// cubes (SGName X portSet) to SG rules +func tcpudpSGCubesToRules(span map[ir.SGName]*netset.PortSet, direction ir.Direction, isTCP bool, l *netset.IPBlock) []*ir.SGRule { + result := make([]*ir.SGRule, 0) + for sgName, portSet := range span { + for _, dstPorts := range portSet.Intervals() { + p, _ := netp.NewTCPUDP(isTCP, netp.MinPort, netp.MaxPort, int(dstPorts.Start()), int(dstPorts.End())) + result = append(result, ir.NewSGRule(direction, sgName, p, l, "")) + } + } + return result +} + +// cubes (SGName X icmpset) to SG rules +func icmpSGCubesToRules(span map[ir.SGName]*netset.ICMPSet, direction ir.Direction, l *netset.IPBlock) []*ir.SGRule { + result := make([]*ir.SGRule, 0) + for sgName, icmpSet := range span { + for _, icmp := range optimize.IcmpsetPartitions(icmpSet) { + result = append(result, ir.NewSGRule(direction, sgName, icmp, l, "")) + } + } + return result +} + +// cubes (slice of SGs) to SG rules +func protocolAllCubesToRules(span []ir.SGName, direction ir.Direction, l *netset.IPBlock) []*ir.SGRule { + result := make([]*ir.SGRule, len(span)) + for i, sgName := range span { + result[i] = ir.NewSGRule(direction, sgName, netp.AnyProtocol{}, l, "") + } + return result +} diff --git a/pkg/synth/common.go b/pkg/synth/common.go index e6e516f3..a9b7b51f 100644 --- a/pkg/synth/common.go +++ b/pkg/synth/common.go @@ -15,6 +15,7 @@ import ( type ( Synthesizer interface { + // generates SGs/nACLs Synth() (ir.Collection, error) } diff --git a/pkg/synth/sg.go b/pkg/synth/sg.go index c90b1783..732303a1 100644 --- a/pkg/synth/sg.go +++ b/pkg/synth/sg.go @@ -9,6 +9,7 @@ import ( "fmt" "github.com/np-guard/models/pkg/netp" + "github.com/np-guard/models/pkg/netset" "github.com/np-guard/vpc-network-config-synthesis/pkg/ir" ) @@ -77,21 +78,15 @@ func (s *SGSynthesizer) generateSGRulesFromConnection(conn *ir.Connection) error } // if the endpoint in internal, a rule will be created to allow traffic. -func (s *SGSynthesizer) allowConnectionEndpoint(localEndpoint, remoteEndpoint *namedAddrs, protocol netp.Protocol, +func (s *SGSynthesizer) allowConnectionEndpoint(localEndpoint, remoteEndpoint *namedAddrs, p netp.Protocol, direction ir.Direction, internalEndpoint bool, ruleExplanation string) { if !internalEndpoint { return } localSGName := ir.SGName(localEndpoint.Name) localSG := s.result.LookupOrCreate(localSGName) - localSG.Attached = []ir.ID{ir.ID(localSGName)} - rule := &ir.SGRule{ - Remote: sgRemote(&s.spec.Defs, remoteEndpoint), - Direction: direction, - Protocol: protocol, - Explanation: ruleExplanation, - } - localSG.Add(rule) + localSG.Targets = []ir.ID{ir.ID(localSGName)} + localSG.Add(ir.NewSGRule(direction, sgRemote(&s.spec.Defs, remoteEndpoint), p, netset.GetCidrAll(), ruleExplanation)) } // generate SGs for blocked endpoints (endpoints that do not appear in Spec) @@ -99,7 +94,7 @@ func (s *SGSynthesizer) generateSGsForBlockedResources() { blockedResources := s.spec.ComputeBlockedResources() for _, resource := range blockedResources { sg := s.result.LookupOrCreate(ir.SGName(resource)) // an empty SG allows no connections - sg.Attached = []ir.ID{resource} + sg.Targets = []ir.ID{resource} } } diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index acf9e3d2..ede1bb67 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -31,3 +31,19 @@ func SortedAllInnerMapsKeys[T, K cmp.Ordered, V any](m map[K]map[T]V) []T { slices.Sort(keys) return keys } + +// GetProperty returns pointer p if it is valid, else it returns the provided default value +// used to get min/max port or icmp type +func GetProperty(p *int64, defaultP int64) int64 { + if p == nil { + return defaultP + } + return *p +} + +func Int64PointerToIntPointer(v *int64) *int { + if v == nil { + return nil + } + return Ptr(int(*v)) +} diff --git a/test/data/optimize_sg_protocols_to_all/config_object.json b/test/data/optimize_sg_protocols_to_all/config_object.json new file mode 100644 index 00000000..e4d7662a --- /dev/null +++ b/test/data/optimize_sg_protocols_to_all/config_object.json @@ -0,0 +1,2220 @@ +{ + "collector_version": "0.11.0", + "provider": "ibm", + "vpcs": [ + { + "classic_access": false, + "created_at": "2024-09-09T09:09:50.000Z", + "crn": "crn:1", + "cse_source_ips": [ + { + "ip": { + "address": "10.22.217.112" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + } + }, + { + "ip": { + "address": "10.12.160.153" + }, + "zone": { + "href": "href:6", + "name": "us-south-2" + } + }, + { + "ip": { + "address": "10.16.253.223" + }, + "zone": { + "href": "href:7", + "name": "us-south-3" + } + } + ], + "default_network_acl": { + "crn": "crn:8", + "href": "href:9", + "id": "id:10", + "name": "capitol-siren-chirpy-doornail" + }, + "default_routing_table": { + "crn": null, + "href": "href:11", + "id": "id:12", + "name": "fiscally-fresh-uncanny-ceramics", + "resource_type": "routing_table" + }, + "default_security_group": { + "crn": "crn:13", + "href": "href:14", + "id": "id:15", + "name": "wombat-hesitate-scorn-subprime" + }, + "dns": { + "enable_hub": false, + "resolution_binding_count": 0, + "resolver": { + "servers": [ + { + "address": "161.26.0.10" + }, + { + "address": "161.26.0.11" + } + ], + "type": "system", + "configuration": "default" + } + }, + "health_reasons": null, + "health_state": "ok", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "vpc", + "status": "available", + "region": "us-south", + "address_prefixes": [ + { + "cidr": "10.240.0.0/18", + "created_at": "2024-09-09T09:09:50.000Z", + "has_subnets": true, + "href": "href:18", + "id": "id:19", + "is_default": true, + "name": "filling-tasty-bacterium-parlor", + "zone": { + "href": "href:5", + "name": "us-south-1" + } + }, + { + "cidr": "10.240.64.0/18", + "created_at": "2024-09-09T09:09:50.000Z", + "has_subnets": false, + "href": "href:20", + "id": "id:21", + "is_default": true, + "name": "relearn-ragweed-goon-feisty", + "zone": { + "href": "href:6", + "name": "us-south-2" + } + }, + { + "cidr": "10.240.128.0/18", + "created_at": "2024-09-09T09:09:50.000Z", + "has_subnets": false, + "href": "href:22", + "id": "id:23", + "is_default": true, + "name": "unruffled-penknife-snowshoe-ninetieth", + "zone": { + "href": "href:7", + "name": "us-south-3" + } + } + ], + "tags": [] + } + ], + "subnets": [ + { + "available_ipv4_address_count": 250, + "created_at": "2024-09-09T09:10:51.000Z", + "crn": "crn:24", + "href": "href:25", + "id": "id:26", + "ip_version": "ipv4", + "ipv4_cidr_block": "10.240.20.0/24", + "name": "subnet2", + "network_acl": { + "crn": "crn:27", + "href": "href:28", + "id": "id:29", + "name": "acl2" + }, + "public_gateway": { + "crn": "crn:30", + "href": "href:31", + "id": "id:32", + "name": "public-gw1", + "resource_type": "public_gateway" + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "subnet", + "routing_table": { + "crn": null, + "href": "href:11", + "id": "id:12", + "name": "fiscally-fresh-uncanny-ceramics", + "resource_type": "routing_table" + }, + "status": "available", + "total_ipv4_address_count": 256, + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "reserved_ips": [ + { + "address": "10.240.20.0", + "auto_delete": false, + "created_at": "2024-09-09T09:10:51.000Z", + "href": "href:33", + "id": "id:34", + "lifecycle_state": "stable", + "name": "ibm-network-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.20.1", + "auto_delete": false, + "created_at": "2024-09-09T09:10:51.000Z", + "href": "href:35", + "id": "id:36", + "lifecycle_state": "stable", + "name": "ibm-default-gateway", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.20.2", + "auto_delete": false, + "created_at": "2024-09-09T09:10:51.000Z", + "href": "href:37", + "id": "id:38", + "lifecycle_state": "stable", + "name": "ibm-dns-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.20.3", + "auto_delete": false, + "created_at": "2024-09-09T09:10:51.000Z", + "href": "href:39", + "id": "id:40", + "lifecycle_state": "stable", + "name": "ibm-reserved-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.20.4", + "auto_delete": true, + "created_at": "2024-09-09T09:11:08.000Z", + "href": "href:41", + "id": "id:42", + "lifecycle_state": "stable", + "name": "startle-percent-embellish-squeegee", + "owner": "user", + "resource_type": "subnet_reserved_ip", + "target": { + "href": "href:43", + "id": "id:44", + "name": "ni2", + "resource_type": "network_interface" + } + }, + { + "address": "10.240.20.255", + "auto_delete": false, + "created_at": "2024-09-09T09:10:51.000Z", + "href": "href:45", + "id": "id:46", + "lifecycle_state": "stable", + "name": "ibm-broadcast-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + } + ], + "tags": [] + }, + { + "available_ipv4_address_count": 250, + "created_at": "2024-09-09T09:10:35.000Z", + "crn": "crn:47", + "href": "href:48", + "id": "id:49", + "ip_version": "ipv4", + "ipv4_cidr_block": "10.240.10.0/24", + "name": "subnet1", + "network_acl": { + "crn": "crn:50", + "href": "href:51", + "id": "id:52", + "name": "acl1" + }, + "public_gateway": { + "crn": "crn:30", + "href": "href:31", + "id": "id:32", + "name": "public-gw1", + "resource_type": "public_gateway" + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "subnet", + "routing_table": { + "crn": null, + "href": "href:11", + "id": "id:12", + "name": "fiscally-fresh-uncanny-ceramics", + "resource_type": "routing_table" + }, + "status": "available", + "total_ipv4_address_count": 256, + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "reserved_ips": [ + { + "address": "10.240.10.0", + "auto_delete": false, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:53", + "id": "id:54", + "lifecycle_state": "stable", + "name": "ibm-network-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.10.1", + "auto_delete": false, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:55", + "id": "id:56", + "lifecycle_state": "stable", + "name": "ibm-default-gateway", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.10.2", + "auto_delete": false, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:57", + "id": "id:58", + "lifecycle_state": "stable", + "name": "ibm-dns-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.10.3", + "auto_delete": false, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:59", + "id": "id:60", + "lifecycle_state": "stable", + "name": "ibm-reserved-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.10.4", + "auto_delete": true, + "created_at": "2024-09-09T09:10:52.000Z", + "href": "href:61", + "id": "id:62", + "lifecycle_state": "stable", + "name": "tableware-sprawl-shrivel-popper", + "owner": "user", + "resource_type": "subnet_reserved_ip", + "target": { + "href": "href:63", + "id": "id:64", + "name": "ni1", + "resource_type": "network_interface" + } + }, + { + "address": "10.240.10.255", + "auto_delete": false, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:65", + "id": "id:66", + "lifecycle_state": "stable", + "name": "ibm-broadcast-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + } + ], + "tags": [] + }, + { + "available_ipv4_address_count": 249, + "created_at": "2024-09-09T09:10:18.000Z", + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "ip_version": "ipv4", + "ipv4_cidr_block": "10.240.30.0/24", + "name": "subnet3", + "network_acl": { + "crn": "crn:70", + "href": "href:71", + "id": "id:72", + "name": "acl3" + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "subnet", + "routing_table": { + "crn": null, + "href": "href:11", + "id": "id:12", + "name": "fiscally-fresh-uncanny-ceramics", + "resource_type": "routing_table" + }, + "status": "available", + "total_ipv4_address_count": 256, + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "reserved_ips": [ + { + "address": "10.240.30.0", + "auto_delete": false, + "created_at": "2024-09-09T09:10:18.000Z", + "href": "href:73", + "id": "id:74", + "lifecycle_state": "stable", + "name": "ibm-network-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.30.1", + "auto_delete": false, + "created_at": "2024-09-09T09:10:18.000Z", + "href": "href:75", + "id": "id:76", + "lifecycle_state": "stable", + "name": "ibm-default-gateway", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.30.2", + "auto_delete": false, + "created_at": "2024-09-09T09:10:18.000Z", + "href": "href:77", + "id": "id:78", + "lifecycle_state": "stable", + "name": "ibm-dns-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.30.3", + "auto_delete": false, + "created_at": "2024-09-09T09:10:18.000Z", + "href": "href:79", + "id": "id:80", + "lifecycle_state": "stable", + "name": "ibm-reserved-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.30.4", + "auto_delete": true, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:81", + "id": "id:82", + "lifecycle_state": "stable", + "name": "disallow-oxidant-etching-selection", + "owner": "user", + "resource_type": "subnet_reserved_ip", + "target": { + "href": "href:83", + "id": "id:84", + "name": "ni3a", + "resource_type": "network_interface" + } + }, + { + "address": "10.240.30.5", + "auto_delete": true, + "created_at": "2024-09-09T09:10:36.000Z", + "href": "href:85", + "id": "id:86", + "lifecycle_state": "stable", + "name": "reheat-joyride-little-overprice", + "owner": "user", + "resource_type": "subnet_reserved_ip", + "target": { + "href": "href:87", + "id": "id:88", + "name": "ni3b", + "resource_type": "network_interface" + } + }, + { + "address": "10.240.30.255", + "auto_delete": false, + "created_at": "2024-09-09T09:10:18.000Z", + "href": "href:89", + "id": "id:90", + "lifecycle_state": "stable", + "name": "ibm-broadcast-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + } + ], + "tags": [] + } + ], + "public_gateways": [ + { + "created_at": "2024-09-09T09:10:14.000Z", + "crn": "crn:30", + "floating_ip": { + "address": "52.118.147.142", + "crn": "crn:91", + "href": "href:92", + "id": "id:93", + "name": "public-gw1" + }, + "href": "href:31", + "id": "id:32", + "name": "public-gw1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "public_gateway", + "status": "available", + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "tags": [] + } + ], + "floating_ips": [ + { + "address": "52.116.129.168", + "created_at": "2024-09-09T09:11:31.000Z", + "crn": "crn:94", + "href": "href:95", + "id": "id:96", + "name": "vsi1-fip", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "status": "available", + "target": { + "href": "href:63", + "id": "id:64", + "name": "ni1", + "primary_ip": { + "address": "10.240.10.4", + "href": "href:61", + "id": "id:62", + "name": "tableware-sprawl-shrivel-popper", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "tags": [] + }, + { + "address": "52.118.147.142", + "created_at": "2024-09-09T09:10:14.000Z", + "crn": "crn:91", + "href": "href:92", + "id": "id:93", + "name": "public-gw1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "status": "available", + "target": { + "href": "href:31", + "id": "id:32", + "name": "public-gw1", + "resource_type": "public_gateway", + "crn": "crn:30" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "tags": [] + } + ], + "network_acls": [ + { + "created_at": "2024-09-09T09:10:15.000Z", + "crn": "crn:27", + "href": "href:28", + "id": "id:29", + "name": "acl2", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "action": "allow", + "before": { + "href": "href:99", + "id": "id:100", + "name": "acl2-out-2" + }, + "created_at": "2024-09-09T09:10:15.000Z", + "destination": "0.0.0.0/0", + "direction": "outbound", + "href": "href:97", + "id": "id:98", + "ip_version": "ipv4", + "name": "acl2-out-1", + "source": "10.240.20.0/24", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:101", + "id": "id:102", + "name": "acl2-in-1" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.10.0/24", + "direction": "outbound", + "href": "href:99", + "id": "id:100", + "ip_version": "ipv4", + "name": "acl2-out-2", + "source": "10.240.20.0/24", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:103", + "id": "id:104", + "name": "acl2-in-2" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.20.0/24", + "direction": "inbound", + "href": "href:101", + "id": "id:102", + "ip_version": "ipv4", + "name": "acl2-in-1", + "source": "0.0.0.0/0", + "protocol": "all" + }, + { + "action": "allow", + "created_at": "2024-09-09T09:10:17.000Z", + "destination": "10.240.20.0/24", + "direction": "inbound", + "href": "href:103", + "id": "id:104", + "ip_version": "ipv4", + "name": "acl2-in-2", + "source": "10.240.10.0/24", + "protocol": "all" + } + ], + "subnets": [ + { + "crn": "crn:24", + "href": "href:25", + "id": "id:26", + "name": "subnet2", + "resource_type": "subnet" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": "2024-09-09T09:10:14.000Z", + "crn": "crn:50", + "href": "href:51", + "id": "id:52", + "name": "acl1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "action": "allow", + "before": { + "href": "href:107", + "id": "id:108", + "name": "acl1-out-2" + }, + "created_at": "2024-09-09T09:10:15.000Z", + "destination": "172.217.22.46/32", + "direction": "outbound", + "href": "href:105", + "id": "id:106", + "ip_version": "ipv4", + "name": "acl1-out-1", + "source": "10.240.10.0/24", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:109", + "id": "id:110", + "name": "acl1-out-3" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.20.0/24", + "direction": "outbound", + "href": "href:107", + "id": "id:108", + "ip_version": "ipv4", + "name": "acl1-out-2", + "source": "10.240.10.0/24", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:111", + "id": "id:112", + "name": "acl1-out-4" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.30.0/24", + "direction": "outbound", + "href": "href:109", + "id": "id:110", + "ip_version": "ipv4", + "name": "acl1-out-3", + "source": "10.240.10.0/24", + "destination_port_max": 443, + "destination_port_min": 443, + "protocol": "tcp", + "source_port_max": 65535, + "source_port_min": 1 + }, + { + "action": "allow", + "before": { + "href": "href:113", + "id": "id:114", + "name": "acl1-in-1" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.30.0/24", + "direction": "outbound", + "href": "href:111", + "id": "id:112", + "ip_version": "ipv4", + "name": "acl1-out-4", + "source": "10.240.10.0/24", + "destination_port_max": 65535, + "destination_port_min": 1, + "protocol": "tcp", + "source_port_max": 443, + "source_port_min": 443 + }, + { + "action": "allow", + "before": { + "href": "href:115", + "id": "id:116", + "name": "acl1-in-2" + }, + "created_at": "2024-09-09T09:10:17.000Z", + "destination": "10.240.10.0/24", + "direction": "inbound", + "href": "href:113", + "id": "id:114", + "ip_version": "ipv4", + "name": "acl1-in-1", + "source": "172.217.22.46/32", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:117", + "id": "id:118", + "name": "acl1-in-3" + }, + "created_at": "2024-09-09T09:10:17.000Z", + "destination": "10.240.10.0/24", + "direction": "inbound", + "href": "href:115", + "id": "id:116", + "ip_version": "ipv4", + "name": "acl1-in-2", + "source": "10.240.20.0/24", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:119", + "id": "id:120", + "name": "acl1-in-4" + }, + "created_at": "2024-09-09T09:10:18.000Z", + "destination": "10.240.10.0/24", + "direction": "inbound", + "href": "href:117", + "id": "id:118", + "ip_version": "ipv4", + "name": "acl1-in-3", + "source": "10.240.30.0/24", + "destination_port_max": 65535, + "destination_port_min": 1, + "protocol": "tcp", + "source_port_max": 443, + "source_port_min": 443 + }, + { + "action": "allow", + "created_at": "2024-09-09T09:10:18.000Z", + "destination": "10.240.10.0/24", + "direction": "inbound", + "href": "href:119", + "id": "id:120", + "ip_version": "ipv4", + "name": "acl1-in-4", + "source": "10.240.30.0/24", + "destination_port_max": 443, + "destination_port_min": 443, + "protocol": "tcp", + "source_port_max": 65535, + "source_port_min": 1 + } + ], + "subnets": [ + { + "crn": "crn:47", + "href": "href:48", + "id": "id:49", + "name": "subnet1", + "resource_type": "subnet" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": "2024-09-09T09:10:14.000Z", + "crn": "crn:70", + "href": "href:71", + "id": "id:72", + "name": "acl3", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "action": "allow", + "before": { + "href": "href:123", + "id": "id:124", + "name": "acl3-out-2" + }, + "created_at": "2024-09-09T09:10:15.000Z", + "destination": "10.240.10.0/24", + "direction": "outbound", + "href": "href:121", + "id": "id:122", + "ip_version": "ipv4", + "name": "acl3-out-1", + "source": "10.240.30.0/24", + "destination_port_max": 443, + "destination_port_min": 443, + "protocol": "tcp", + "source_port_max": 65535, + "source_port_min": 1 + }, + { + "action": "allow", + "before": { + "href": "href:125", + "id": "id:126", + "name": "acl3-in-1" + }, + "created_at": "2024-09-09T09:10:15.000Z", + "destination": "10.240.10.0/24", + "direction": "outbound", + "href": "href:123", + "id": "id:124", + "ip_version": "ipv4", + "name": "acl3-out-2", + "source": "10.240.30.0/24", + "destination_port_max": 65535, + "destination_port_min": 1, + "protocol": "tcp", + "source_port_max": 443, + "source_port_min": 443 + }, + { + "action": "allow", + "before": { + "href": "href:127", + "id": "id:128", + "name": "acl3-in-2" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.30.0/24", + "direction": "inbound", + "href": "href:125", + "id": "id:126", + "ip_version": "ipv4", + "name": "acl3-in-1", + "source": "10.240.10.0/24", + "destination_port_max": 443, + "destination_port_min": 443, + "protocol": "tcp", + "source_port_max": 65535, + "source_port_min": 1 + }, + { + "action": "allow", + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.30.0/24", + "direction": "inbound", + "href": "href:127", + "id": "id:128", + "ip_version": "ipv4", + "name": "acl3-in-2", + "source": "10.240.10.0/24", + "destination_port_max": 65535, + "destination_port_min": 1, + "protocol": "tcp", + "source_port_max": 443, + "source_port_min": 443 + } + ], + "subnets": [ + { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": "2024-09-09T09:09:50.000Z", + "crn": "crn:8", + "href": "href:9", + "id": "id:10", + "name": "capitol-siren-chirpy-doornail", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "action": "allow", + "before": { + "href": "href:131", + "id": "id:132", + "name": "allow-outbound" + }, + "created_at": "2024-09-09T09:09:50.000Z", + "destination": "0.0.0.0/0", + "direction": "inbound", + "href": "href:129", + "id": "id:130", + "ip_version": "ipv4", + "name": "allow-inbound", + "source": "0.0.0.0/0", + "protocol": "all" + }, + { + "action": "allow", + "created_at": "2024-09-09T09:09:50.000Z", + "destination": "0.0.0.0/0", + "direction": "outbound", + "href": "href:131", + "id": "id:132", + "ip_version": "ipv4", + "name": "allow-outbound", + "source": "0.0.0.0/0", + "protocol": "all" + } + ], + "subnets": [], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + } + ], + "security_groups": [ + { + "created_at": "2024-09-09T09:10:14.000Z", + "crn": "crn:133", + "href": "href:134", + "id": "id:135", + "name": "sg1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "direction": "inbound", + "href": "href:136", + "id": "id:137", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.0/0" + }, + "protocol": "all" + }, + { + "direction": "outbound", + "href": "href:138", + "id": "id:139", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.0/0" + }, + "protocol": "all" + } + ], + "targets": [], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": "2024-09-09T09:09:50.000Z", + "crn": "crn:13", + "href": "href:14", + "id": "id:15", + "name": "wombat-hesitate-scorn-subprime", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "direction": "outbound", + "href": "href:140", + "id": "id:141", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.0/0" + }, + "protocol": "all" + }, + { + "direction": "inbound", + "href": "href:142", + "id": "id:143", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "crn": "crn:13", + "href": "href:14", + "id": "id:15", + "name": "wombat-hesitate-scorn-subprime" + }, + "protocol": "all" + } + ], + "targets": [], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": null, + "crn": "fake:crn:7", + "href": "fake:href:7", + "id": "fake:id:7", + "name": "test-vpc1--vsi2", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "direction": "inbound", + "href": "fake:href:1", + "id": "fake:id:1", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "crn": "fake:crn:2", + "href": "fake:href:2", + "id": "fake:id:2", + "name": "test-vpc1--vsi1" + }, + "protocol": "icmp" + }, + { + "direction": "inbound", + "href": "fake:href:3", + "id": "fake:id:3", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "crn": "fake:crn:2", + "href": "fake:href:2", + "id": "fake:id:2", + "name": "test-vpc1--vsi1" + }, + "port_max": 65535, + "port_min": 1, + "protocol": "tcp" + }, + { + "direction": "inbound", + "href": "fake:href:4", + "id": "fake:id:4", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "crn": "fake:crn:2", + "href": "fake:href:2", + "id": "fake:id:2", + "name": "test-vpc1--vsi1" + }, + "port_max": 100, + "port_min": 1, + "protocol": "udp" + }, + { + "direction": "inbound", + "href": "fake:href:5", + "id": "fake:id:5", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "crn": "fake:crn:2", + "href": "fake:href:2", + "id": "fake:id:2", + "name": "test-vpc1--vsi1" + }, + "port_max": 150, + "port_min": 50, + "protocol": "udp" + }, + { + "direction": "inbound", + "href": "fake:href:6", + "id": "fake:id:6", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "crn": "fake:crn:2", + "href": "fake:href:2", + "id": "fake:id:2", + "name": "test-vpc1--vsi1" + }, + "port_max": 65535, + "port_min": 151, + "protocol": "udp" + } + ], + "targets": [ + { + "href": "href:43", + "id": "id:44", + "name": "ni2", + "resource_type": "network_interface" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": null, + "crn": "fake:crn:2", + "href": "fake:href:2", + "id": "fake:id:2", + "name": "test-vpc1--vsi1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "direction": "outbound", + "href": "fake:href:8", + "id": "fake:id:8", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.0/30" + }, + "protocol": "icmp" + }, + { + "direction": "outbound", + "href": "fake:href:9", + "id": "fake:id:9", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.0/31" + }, + "port_max": 65535, + "port_min": 1, + "protocol": "tcp" + }, + { + "direction": "outbound", + "href": "fake:href:10", + "id": "fake:id:10", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.0/31" + }, + "port_max": 100, + "port_min": 1, + "protocol": "udp" + }, + { + "direction": "outbound", + "href": "fake:href:11", + "id": "fake:id:11", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.0/31" + }, + "port_max": 150, + "port_min": 50, + "protocol": "udp" + }, + { + "direction": "outbound", + "href": "fake:href:12", + "id": "fake:id:12", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.0/31" + }, + "port_max": 65535, + "port_min": 151, + "protocol": "udp" + }, + { + "direction": "outbound", + "href": "fake:href:13", + "id": "fake:id:13", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "crn": "fake:crn:7", + "href": "fake:href:7", + "id": "fake:id:7", + "name": "test-vpc1--vsi2" + }, + "protocol": "icmp" + }, + { + "direction": "outbound", + "href": "fake:href:14", + "id": "fake:id:14", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "crn": "fake:crn:7", + "href": "fake:href:7", + "id": "fake:id:7", + "name": "test-vpc1--vsi2" + }, + "port_max": 65535, + "port_min": 1, + "protocol": "tcp" + }, + { + "direction": "outbound", + "href": "fake:href:15", + "id": "fake:id:15", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "crn": "fake:crn:7", + "href": "fake:href:7", + "id": "fake:id:7", + "name": "test-vpc1--vsi2" + }, + "port_max": 100, + "port_min": 1, + "protocol": "udp" + }, + { + "direction": "outbound", + "href": "fake:href:16", + "id": "fake:id:16", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "crn": "fake:crn:7", + "href": "fake:href:7", + "id": "fake:id:7", + "name": "test-vpc1--vsi2" + }, + "port_max": 150, + "port_min": 50, + "protocol": "udp" + }, + { + "direction": "outbound", + "href": "fake:href:17", + "id": "fake:id:17", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "crn": "fake:crn:7", + "href": "fake:href:7", + "id": "fake:id:7", + "name": "test-vpc1--vsi2" + }, + "port_max": 65535, + "port_min": 151, + "protocol": "udp" + } + ], + "targets": [ + { + "href": "href:63", + "id": "id:64", + "name": "ni1", + "resource_type": "network_interface" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": null, + "crn": "fake:crn:18", + "href": "fake:href:18", + "id": "fake:id:18", + "name": "test-vpc1--vsi3b", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [], + "targets": [ + { + "href": "href:87", + "id": "id:88", + "name": "ni3b", + "resource_type": "network_interface" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": null, + "crn": "fake:crn:19", + "href": "fake:href:19", + "id": "fake:id:19", + "name": "test-vpc1--vsi3a", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [], + "targets": [ + { + "href": "href:83", + "id": "id:84", + "name": "ni3a", + "resource_type": "network_interface" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + } + ], + "endpoint_gateways": [], + "instances": [ + { + "availability_policy": { + "host_failure": "restart" + }, + "bandwidth": 4000, + "boot_volume_attachment": { + "device": { + "id": "id:149" + }, + "href": "href:147", + "id": "id:148", + "name": "falsetto-snowstorm-bankbook-agreement", + "volume": { + "crn": "crn:150", + "href": "href:151", + "id": "id:152", + "name": "prawn-trusting-pasty-dental", + "resource_type": "volume" + } + }, + "confidential_compute_mode": "disabled", + "created_at": "2024-09-09T09:11:07.000Z", + "crn": "crn:144", + "disks": [], + "enable_secure_boot": false, + "health_reasons": [], + "health_state": "ok", + "href": "href:145", + "id": "id:146", + "image": { + "crn": "crn:153", + "href": "href:154", + "id": "id:155", + "name": "server-9080", + "resource_type": "image" + }, + "lifecycle_reasons": [], + "lifecycle_state": "stable", + "memory": 4, + "metadata_service": { + "enabled": false, + "protocol": "http", + "response_hop_limit": 1 + }, + "name": "vsi2", + "network_attachments": [], + "numa_count": 1, + "primary_network_interface": { + "href": "href:43", + "id": "id:44", + "name": "ni2", + "primary_ip": { + "address": "10.240.20.4", + "href": "href:41", + "id": "id:42", + "name": "startle-percent-embellish-squeegee", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "subnet": { + "crn": "crn:24", + "href": "href:25", + "id": "id:26", + "name": "subnet2", + "resource_type": "subnet" + } + }, + "profile": { + "href": "href:156", + "name": "cx2-2x4", + "resource_type": "instance_profile" + }, + "reservation_affinity": { + "policy": "disabled", + "pool": [] + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "instance", + "startable": true, + "status": "running", + "status_reasons": [], + "total_network_bandwidth": 3000, + "total_volume_bandwidth": 1000, + "vcpu": { + "architecture": "amd64", + "count": 2, + "manufacturer": "intel" + }, + "volume_attachments": [ + { + "device": { + "id": "id:149" + }, + "href": "href:147", + "id": "id:148", + "name": "falsetto-snowstorm-bankbook-agreement", + "volume": { + "crn": "crn:150", + "href": "href:151", + "id": "id:152", + "name": "prawn-trusting-pasty-dental", + "resource_type": "volume" + } + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "network_interfaces": [ + { + "allow_ip_spoofing": false, + "created_at": "2024-09-09T09:11:07.000Z", + "floating_ips": [], + "href": "href:43", + "id": "id:44", + "name": "ni2", + "port_speed": 3000, + "primary_ip": { + "address": "10.240.20.4", + "href": "href:41", + "id": "id:42", + "name": "startle-percent-embellish-squeegee", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "security_groups": [ + { + "crn": "fake:crn:7", + "href": "fake:href:7", + "id": "fake:id:7", + "name": "test-vpc1--vsi2" + } + ], + "status": "available", + "subnet": { + "crn": "crn:24", + "href": "href:25", + "id": "id:26", + "name": "subnet2", + "resource_type": "subnet" + }, + "type": "primary" + } + ], + "tags": [] + }, + { + "availability_policy": { + "host_failure": "restart" + }, + "bandwidth": 4000, + "boot_volume_attachment": { + "device": { + "id": "id:162" + }, + "href": "href:160", + "id": "id:161", + "name": "outskirts-oversized-roundish-ludicrous", + "volume": { + "crn": "crn:163", + "href": "href:164", + "id": "id:165", + "name": "family-tackling-foothold-train", + "resource_type": "volume" + } + }, + "confidential_compute_mode": "disabled", + "created_at": "2024-09-09T09:10:52.000Z", + "crn": "crn:157", + "disks": [], + "enable_secure_boot": false, + "health_reasons": [], + "health_state": "ok", + "href": "href:158", + "id": "id:159", + "image": { + "crn": "crn:153", + "href": "href:154", + "id": "id:155", + "name": "server-9080", + "resource_type": "image" + }, + "lifecycle_reasons": [], + "lifecycle_state": "stable", + "memory": 4, + "metadata_service": { + "enabled": false, + "protocol": "http", + "response_hop_limit": 1 + }, + "name": "vsi1", + "network_attachments": [], + "numa_count": 1, + "primary_network_interface": { + "href": "href:63", + "id": "id:64", + "name": "ni1", + "primary_ip": { + "address": "10.240.10.4", + "href": "href:61", + "id": "id:62", + "name": "tableware-sprawl-shrivel-popper", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "subnet": { + "crn": "crn:47", + "href": "href:48", + "id": "id:49", + "name": "subnet1", + "resource_type": "subnet" + } + }, + "profile": { + "href": "href:156", + "name": "cx2-2x4", + "resource_type": "instance_profile" + }, + "reservation_affinity": { + "policy": "disabled", + "pool": [] + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "instance", + "startable": true, + "status": "running", + "status_reasons": [], + "total_network_bandwidth": 3000, + "total_volume_bandwidth": 1000, + "vcpu": { + "architecture": "amd64", + "count": 2, + "manufacturer": "intel" + }, + "volume_attachments": [ + { + "device": { + "id": "id:162" + }, + "href": "href:160", + "id": "id:161", + "name": "outskirts-oversized-roundish-ludicrous", + "volume": { + "crn": "crn:163", + "href": "href:164", + "id": "id:165", + "name": "family-tackling-foothold-train", + "resource_type": "volume" + } + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "network_interfaces": [ + { + "allow_ip_spoofing": false, + "created_at": "2024-09-09T09:10:52.000Z", + "floating_ips": [ + { + "address": "52.116.129.168", + "crn": "crn:94", + "href": "href:95", + "id": "id:96", + "name": "vsi1-fip" + } + ], + "href": "href:63", + "id": "id:64", + "name": "ni1", + "port_speed": 3000, + "primary_ip": { + "address": "10.240.10.4", + "href": "href:61", + "id": "id:62", + "name": "tableware-sprawl-shrivel-popper", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "security_groups": [ + { + "crn": "fake:crn:2", + "href": "fake:href:2", + "id": "fake:id:2", + "name": "test-vpc1--vsi1" + } + ], + "status": "available", + "subnet": { + "crn": "crn:47", + "href": "href:48", + "id": "id:49", + "name": "subnet1", + "resource_type": "subnet" + }, + "type": "primary" + } + ], + "tags": [] + }, + { + "availability_policy": { + "host_failure": "restart" + }, + "bandwidth": 4000, + "boot_volume_attachment": { + "device": { + "id": "id:171" + }, + "href": "href:169", + "id": "id:170", + "name": "camera-yam-headfirst-scabiosa", + "volume": { + "crn": "crn:172", + "href": "href:173", + "id": "id:174", + "name": "sprinkler-avenue-playset-dislodge", + "resource_type": "volume" + } + }, + "confidential_compute_mode": "disabled", + "created_at": "2024-09-09T09:10:35.000Z", + "crn": "crn:166", + "disks": [], + "enable_secure_boot": false, + "health_reasons": [], + "health_state": "ok", + "href": "href:167", + "id": "id:168", + "image": { + "crn": "crn:153", + "href": "href:154", + "id": "id:155", + "name": "server-9080", + "resource_type": "image" + }, + "lifecycle_reasons": [], + "lifecycle_state": "stable", + "memory": 4, + "metadata_service": { + "enabled": false, + "protocol": "http", + "response_hop_limit": 1 + }, + "name": "vsi3b", + "network_attachments": [], + "numa_count": 1, + "primary_network_interface": { + "href": "href:87", + "id": "id:88", + "name": "ni3b", + "primary_ip": { + "address": "10.240.30.5", + "href": "href:85", + "id": "id:86", + "name": "reheat-joyride-little-overprice", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "subnet": { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + } + }, + "profile": { + "href": "href:156", + "name": "cx2-2x4", + "resource_type": "instance_profile" + }, + "reservation_affinity": { + "policy": "disabled", + "pool": [] + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "instance", + "startable": true, + "status": "running", + "status_reasons": [], + "total_network_bandwidth": 3000, + "total_volume_bandwidth": 1000, + "vcpu": { + "architecture": "amd64", + "count": 2, + "manufacturer": "intel" + }, + "volume_attachments": [ + { + "device": { + "id": "id:171" + }, + "href": "href:169", + "id": "id:170", + "name": "camera-yam-headfirst-scabiosa", + "volume": { + "crn": "crn:172", + "href": "href:173", + "id": "id:174", + "name": "sprinkler-avenue-playset-dislodge", + "resource_type": "volume" + } + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "network_interfaces": [ + { + "allow_ip_spoofing": false, + "created_at": "2024-09-09T09:10:34.000Z", + "floating_ips": [], + "href": "href:87", + "id": "id:88", + "name": "ni3b", + "port_speed": 3000, + "primary_ip": { + "address": "10.240.30.5", + "href": "href:85", + "id": "id:86", + "name": "reheat-joyride-little-overprice", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "security_groups": [ + { + "crn": "fake:crn:18", + "href": "fake:href:18", + "id": "fake:id:18", + "name": "test-vpc1--vsi3b" + } + ], + "status": "available", + "subnet": { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + }, + "type": "primary" + } + ], + "tags": [] + }, + { + "availability_policy": { + "host_failure": "restart" + }, + "bandwidth": 4000, + "boot_volume_attachment": { + "device": { + "id": "id:180" + }, + "href": "href:178", + "id": "id:179", + "name": "cryptic-cork-saponify-lively", + "volume": { + "crn": "crn:181", + "href": "href:182", + "id": "id:183", + "name": "appraisal-mountains-itinerary-twine", + "resource_type": "volume" + } + }, + "confidential_compute_mode": "disabled", + "created_at": "2024-09-09T09:10:34.000Z", + "crn": "crn:175", + "disks": [], + "enable_secure_boot": false, + "health_reasons": [], + "health_state": "ok", + "href": "href:176", + "id": "id:177", + "image": { + "crn": "crn:153", + "href": "href:154", + "id": "id:155", + "name": "server-9080", + "resource_type": "image" + }, + "lifecycle_reasons": [], + "lifecycle_state": "stable", + "memory": 4, + "metadata_service": { + "enabled": false, + "protocol": "http", + "response_hop_limit": 1 + }, + "name": "vsi3a", + "network_attachments": [], + "numa_count": 1, + "primary_network_interface": { + "href": "href:83", + "id": "id:84", + "name": "ni3a", + "primary_ip": { + "address": "10.240.30.4", + "href": "href:81", + "id": "id:82", + "name": "disallow-oxidant-etching-selection", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "subnet": { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + } + }, + "profile": { + "href": "href:156", + "name": "cx2-2x4", + "resource_type": "instance_profile" + }, + "reservation_affinity": { + "policy": "disabled", + "pool": [] + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "instance", + "startable": true, + "status": "running", + "status_reasons": [], + "total_network_bandwidth": 3000, + "total_volume_bandwidth": 1000, + "vcpu": { + "architecture": "amd64", + "count": 2, + "manufacturer": "intel" + }, + "volume_attachments": [ + { + "device": { + "id": "id:180" + }, + "href": "href:178", + "id": "id:179", + "name": "cryptic-cork-saponify-lively", + "volume": { + "crn": "crn:181", + "href": "href:182", + "id": "id:183", + "name": "appraisal-mountains-itinerary-twine", + "resource_type": "volume" + } + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "network_interfaces": [ + { + "allow_ip_spoofing": false, + "created_at": "2024-09-09T09:10:34.000Z", + "floating_ips": [], + "href": "href:83", + "id": "id:84", + "name": "ni3a", + "port_speed": 3000, + "primary_ip": { + "address": "10.240.30.4", + "href": "href:81", + "id": "id:82", + "name": "disallow-oxidant-etching-selection", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "security_groups": [ + { + "crn": "fake:crn:19", + "href": "fake:href:19", + "id": "fake:id:19", + "name": "test-vpc1--vsi3a" + } + ], + "status": "available", + "subnet": { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + }, + "type": "primary" + } + ], + "tags": [] + } + ], + "virtual_nis": null, + "routing_tables": [ + { + "accept_routes_from": [ + { + "resource_type": "vpn_gateway" + }, + { + "resource_type": "vpn_server" + } + ], + "advertise_routes_to": [], + "created_at": "2024-09-09T09:09:51.000Z", + "crn": null, + "href": "href:11", + "id": "id:12", + "is_default": true, + "lifecycle_state": "stable", + "name": "fiscally-fresh-uncanny-ceramics", + "resource_group": null, + "resource_type": "routing_table", + "route_direct_link_ingress": false, + "route_internet_ingress": false, + "route_transit_gateway_ingress": false, + "route_vpc_zone_ingress": false, + "subnets": [ + { + "crn": "crn:24", + "href": "href:25", + "id": "id:26", + "name": "subnet2", + "resource_type": "subnet" + }, + { + "crn": "crn:47", + "href": "href:48", + "id": "id:49", + "name": "subnet1", + "resource_type": "subnet" + }, + { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + } + ], + "routes": [], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + } + } + ], + "load_balancers": [], + "transit_connections": null, + "transit_gateways": null, + "iks_clusters": [] +} \ No newline at end of file diff --git a/test/data/optimize_sg_protocols_to_all/conn_spec.json b/test/data/optimize_sg_protocols_to_all/conn_spec.json new file mode 100644 index 00000000..4b184550 --- /dev/null +++ b/test/data/optimize_sg_protocols_to_all/conn_spec.json @@ -0,0 +1,170 @@ +{ + "externals": { + "e1": "0.0.0.0/31", + "e2": "0.0.0.0/30" + }, + "required-connections": [ + { + "src": { + "name": "vsi1", + "type": "instance" + }, + "dst": { + "name": "e2", + "type": "external" + }, + "allowed-protocols": [ + { + "protocol": "ICMP" + } + ] + }, + { + "src": { + "name": "vsi1", + "type": "instance" + }, + "dst": { + "name": "e1", + "type": "external" + }, + "allowed-protocols": [ + { + "protocol": "TCP" + } + ] + }, + { + "src": { + "name": "vsi1", + "type": "instance" + }, + "dst": { + "name": "e1", + "type": "external" + }, + "allowed-protocols": [ + { + "protocol": "UDP", + "min_destination_port": 1, + "max_destination_port": 100 + } + ] + }, + { + "src": { + "name": "vsi1", + "type": "instance" + }, + "dst": { + "name": "e1", + "type": "external" + }, + "allowed-protocols": [ + { + "protocol": "UDP", + "min_destination_port": 50, + "max_destination_port": 150 + } + ] + }, + { + "src": { + "name": "vsi1", + "type": "instance" + }, + "dst": { + "name": "e1", + "type": "external" + }, + "allowed-protocols": [ + { + "protocol": "UDP", + "min_destination_port": 151, + "max_destination_port": 65535 + } + ] + }, + { + "src": { + "name": "vsi1", + "type": "instance" + }, + "dst": { + "name": "vsi2", + "type": "instance" + }, + "allowed-protocols": [ + { + "protocol": "ICMP" + } + ] + }, + { + "src": { + "name": "vsi1", + "type": "instance" + }, + "dst": { + "name": "vsi2", + "type": "instance" + }, + "allowed-protocols": [ + { + "protocol": "TCP" + } + ] + }, + { + "src": { + "name": "vsi1", + "type": "instance" + }, + "dst": { + "name": "vsi2", + "type": "instance" + }, + "allowed-protocols": [ + { + "protocol": "UDP", + "min_destination_port": 1, + "max_destination_port": 100 + } + ] + }, + { + "src": { + "name": "vsi1", + "type": "instance" + }, + "dst": { + "name": "vsi2", + "type": "instance" + }, + "allowed-protocols": [ + { + "protocol": "UDP", + "min_destination_port": 50, + "max_destination_port": 150 + } + ] + }, + { + "src": { + "name": "vsi1", + "type": "instance" + }, + "dst": { + "name": "vsi2", + "type": "instance" + }, + "allowed-protocols": [ + { + "protocol": "UDP", + "min_destination_port": 151, + "max_destination_port": 65535 + } + ] + } + ] +} diff --git a/test/data/optimize_sg_protocols_to_all/details.txt b/test/data/optimize_sg_protocols_to_all/details.txt new file mode 100644 index 00000000..09b14960 --- /dev/null +++ b/test/data/optimize_sg_protocols_to_all/details.txt @@ -0,0 +1,17 @@ +vsi1 --> 0.0.0.0/30 (icmp) +vsi1 --> 0.0.0.0/31 (tcp) +vsi1 --> 0.0.0.0/31 (udp ports 1-100) +vsi1 --> 0.0.0.0/31 (udp ports 50-150) +vsi1 --> 0.0.0.0/31 (udp ports 151-65535) + +vsi1 --> vsi2 (icmp) +vsi1 --> vsi2 (tcp) +vsi1 --> vsi2 (udp ports 1-100) +vsi1 --> vsi2 (udp ports 50-150) +vsi1 --> vsi2 (udp ports 151-65535) + +==================================== + +vsi1 --> 0.0.0.0/31 (all protocol) +vsi1 --> 0.0.0.0/30 (icmp) +vsi1 --> vsi2 (all protocol) \ No newline at end of file diff --git a/test/data/optimize_sg_redundant/config_object.json b/test/data/optimize_sg_redundant/config_object.json new file mode 100644 index 00000000..e9dd5c87 --- /dev/null +++ b/test/data/optimize_sg_redundant/config_object.json @@ -0,0 +1,2023 @@ +{ + "collector_version": "0.11.0", + "provider": "ibm", + "vpcs": [ + { + "classic_access": false, + "created_at": "2024-09-09T09:09:50.000Z", + "crn": "crn:1", + "cse_source_ips": [ + { + "ip": { + "address": "10.22.217.112" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + } + }, + { + "ip": { + "address": "10.12.160.153" + }, + "zone": { + "href": "href:6", + "name": "us-south-2" + } + }, + { + "ip": { + "address": "10.16.253.223" + }, + "zone": { + "href": "href:7", + "name": "us-south-3" + } + } + ], + "default_network_acl": { + "crn": "crn:8", + "href": "href:9", + "id": "id:10", + "name": "capitol-siren-chirpy-doornail" + }, + "default_routing_table": { + "href": "href:11", + "id": "id:12", + "name": "fiscally-fresh-uncanny-ceramics", + "resource_type": "routing_table" + }, + "default_security_group": { + "crn": "crn:13", + "href": "href:14", + "id": "id:15", + "name": "wombat-hesitate-scorn-subprime" + }, + "dns": { + "enable_hub": false, + "resolution_binding_count": 0, + "resolver": { + "servers": [ + { + "address": "161.26.0.10" + }, + { + "address": "161.26.0.11" + } + ], + "type": "system", + "configuration": "default" + } + }, + "health_reasons": null, + "health_state": "ok", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "vpc", + "status": "available", + "region": "us-south", + "address_prefixes": [ + { + "cidr": "10.240.0.0/18", + "created_at": "2024-09-09T09:09:50.000Z", + "has_subnets": true, + "href": "href:18", + "id": "id:19", + "is_default": true, + "name": "filling-tasty-bacterium-parlor", + "zone": { + "href": "href:5", + "name": "us-south-1" + } + }, + { + "cidr": "10.240.64.0/18", + "created_at": "2024-09-09T09:09:50.000Z", + "has_subnets": false, + "href": "href:20", + "id": "id:21", + "is_default": true, + "name": "relearn-ragweed-goon-feisty", + "zone": { + "href": "href:6", + "name": "us-south-2" + } + }, + { + "cidr": "10.240.128.0/18", + "created_at": "2024-09-09T09:09:50.000Z", + "has_subnets": false, + "href": "href:22", + "id": "id:23", + "is_default": true, + "name": "unruffled-penknife-snowshoe-ninetieth", + "zone": { + "href": "href:7", + "name": "us-south-3" + } + } + ], + "tags": [] + } + ], + "subnets": [ + { + "available_ipv4_address_count": 250, + "created_at": "2024-09-09T09:10:51.000Z", + "crn": "crn:24", + "href": "href:25", + "id": "id:26", + "ip_version": "ipv4", + "ipv4_cidr_block": "10.240.20.0/24", + "name": "subnet2", + "network_acl": { + "crn": "crn:27", + "href": "href:28", + "id": "id:29", + "name": "acl2" + }, + "public_gateway": { + "crn": "crn:30", + "href": "href:31", + "id": "id:32", + "name": "public-gw1", + "resource_type": "public_gateway" + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "subnet", + "routing_table": { + "href": "href:11", + "id": "id:12", + "name": "fiscally-fresh-uncanny-ceramics", + "resource_type": "routing_table" + }, + "status": "available", + "total_ipv4_address_count": 256, + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "reserved_ips": [ + { + "address": "10.240.20.0", + "auto_delete": false, + "created_at": "2024-09-09T09:10:51.000Z", + "href": "href:33", + "id": "id:34", + "lifecycle_state": "stable", + "name": "ibm-network-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.20.1", + "auto_delete": false, + "created_at": "2024-09-09T09:10:51.000Z", + "href": "href:35", + "id": "id:36", + "lifecycle_state": "stable", + "name": "ibm-default-gateway", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.20.2", + "auto_delete": false, + "created_at": "2024-09-09T09:10:51.000Z", + "href": "href:37", + "id": "id:38", + "lifecycle_state": "stable", + "name": "ibm-dns-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.20.3", + "auto_delete": false, + "created_at": "2024-09-09T09:10:51.000Z", + "href": "href:39", + "id": "id:40", + "lifecycle_state": "stable", + "name": "ibm-reserved-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.20.4", + "auto_delete": true, + "created_at": "2024-09-09T09:11:08.000Z", + "href": "href:41", + "id": "id:42", + "lifecycle_state": "stable", + "name": "startle-percent-embellish-squeegee", + "owner": "user", + "resource_type": "subnet_reserved_ip", + "target": { + "href": "href:43", + "id": "id:44", + "name": "ni2", + "resource_type": "network_interface" + } + }, + { + "address": "10.240.20.255", + "auto_delete": false, + "created_at": "2024-09-09T09:10:51.000Z", + "href": "href:45", + "id": "id:46", + "lifecycle_state": "stable", + "name": "ibm-broadcast-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + } + ], + "tags": [] + }, + { + "available_ipv4_address_count": 250, + "created_at": "2024-09-09T09:10:35.000Z", + "crn": "crn:47", + "href": "href:48", + "id": "id:49", + "ip_version": "ipv4", + "ipv4_cidr_block": "10.240.10.0/24", + "name": "subnet1", + "network_acl": { + "crn": "crn:50", + "href": "href:51", + "id": "id:52", + "name": "acl1" + }, + "public_gateway": { + "crn": "crn:30", + "href": "href:31", + "id": "id:32", + "name": "public-gw1", + "resource_type": "public_gateway" + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "subnet", + "routing_table": { + "href": "href:11", + "id": "id:12", + "name": "fiscally-fresh-uncanny-ceramics", + "resource_type": "routing_table" + }, + "status": "available", + "total_ipv4_address_count": 256, + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "reserved_ips": [ + { + "address": "10.240.10.0", + "auto_delete": false, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:53", + "id": "id:54", + "lifecycle_state": "stable", + "name": "ibm-network-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.10.1", + "auto_delete": false, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:55", + "id": "id:56", + "lifecycle_state": "stable", + "name": "ibm-default-gateway", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.10.2", + "auto_delete": false, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:57", + "id": "id:58", + "lifecycle_state": "stable", + "name": "ibm-dns-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.10.3", + "auto_delete": false, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:59", + "id": "id:60", + "lifecycle_state": "stable", + "name": "ibm-reserved-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.10.4", + "auto_delete": true, + "created_at": "2024-09-09T09:10:52.000Z", + "href": "href:61", + "id": "id:62", + "lifecycle_state": "stable", + "name": "tableware-sprawl-shrivel-popper", + "owner": "user", + "resource_type": "subnet_reserved_ip", + "target": { + "href": "href:63", + "id": "id:64", + "name": "ni1", + "resource_type": "network_interface" + } + }, + { + "address": "10.240.10.255", + "auto_delete": false, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:65", + "id": "id:66", + "lifecycle_state": "stable", + "name": "ibm-broadcast-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + } + ], + "tags": [] + }, + { + "available_ipv4_address_count": 249, + "created_at": "2024-09-09T09:10:18.000Z", + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "ip_version": "ipv4", + "ipv4_cidr_block": "10.240.30.0/24", + "name": "subnet3", + "network_acl": { + "crn": "crn:70", + "href": "href:71", + "id": "id:72", + "name": "acl3" + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "subnet", + "routing_table": { + "href": "href:11", + "id": "id:12", + "name": "fiscally-fresh-uncanny-ceramics", + "resource_type": "routing_table" + }, + "status": "available", + "total_ipv4_address_count": 256, + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "reserved_ips": [ + { + "address": "10.240.30.0", + "auto_delete": false, + "created_at": "2024-09-09T09:10:18.000Z", + "href": "href:73", + "id": "id:74", + "lifecycle_state": "stable", + "name": "ibm-network-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.30.1", + "auto_delete": false, + "created_at": "2024-09-09T09:10:18.000Z", + "href": "href:75", + "id": "id:76", + "lifecycle_state": "stable", + "name": "ibm-default-gateway", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.30.2", + "auto_delete": false, + "created_at": "2024-09-09T09:10:18.000Z", + "href": "href:77", + "id": "id:78", + "lifecycle_state": "stable", + "name": "ibm-dns-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.30.3", + "auto_delete": false, + "created_at": "2024-09-09T09:10:18.000Z", + "href": "href:79", + "id": "id:80", + "lifecycle_state": "stable", + "name": "ibm-reserved-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.30.4", + "auto_delete": true, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:81", + "id": "id:82", + "lifecycle_state": "stable", + "name": "disallow-oxidant-etching-selection", + "owner": "user", + "resource_type": "subnet_reserved_ip", + "target": { + "href": "href:83", + "id": "id:84", + "name": "ni3a", + "resource_type": "network_interface" + } + }, + { + "address": "10.240.30.5", + "auto_delete": true, + "created_at": "2024-09-09T09:10:36.000Z", + "href": "href:85", + "id": "id:86", + "lifecycle_state": "stable", + "name": "reheat-joyride-little-overprice", + "owner": "user", + "resource_type": "subnet_reserved_ip", + "target": { + "href": "href:87", + "id": "id:88", + "name": "ni3b", + "resource_type": "network_interface" + } + }, + { + "address": "10.240.30.255", + "auto_delete": false, + "created_at": "2024-09-09T09:10:18.000Z", + "href": "href:89", + "id": "id:90", + "lifecycle_state": "stable", + "name": "ibm-broadcast-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + } + ], + "tags": [] + } + ], + "public_gateways": [ + { + "created_at": "2024-09-09T09:10:14.000Z", + "crn": "crn:30", + "floating_ip": { + "address": "52.118.147.142", + "crn": "crn:91", + "href": "href:92", + "id": "id:93", + "name": "public-gw1" + }, + "href": "href:31", + "id": "id:32", + "name": "public-gw1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "public_gateway", + "status": "available", + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "tags": [] + } + ], + "floating_ips": [ + { + "address": "52.116.129.168", + "created_at": "2024-09-09T09:11:31.000Z", + "crn": "crn:94", + "href": "href:95", + "id": "id:96", + "name": "vsi1-fip", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "status": "available", + "target": { + "href": "href:63", + "id": "id:64", + "name": "ni1", + "primary_ip": { + "address": "10.240.10.4", + "href": "href:61", + "id": "id:62", + "name": "tableware-sprawl-shrivel-popper", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "tags": [] + }, + { + "address": "52.118.147.142", + "created_at": "2024-09-09T09:10:14.000Z", + "crn": "crn:91", + "href": "href:92", + "id": "id:93", + "name": "public-gw1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "status": "available", + "target": { + "href": "href:31", + "id": "id:32", + "name": "public-gw1", + "resource_type": "public_gateway", + "crn": "crn:30" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "tags": [] + } + ], + "network_acls": [ + { + "created_at": "2024-09-09T09:10:15.000Z", + "crn": "crn:27", + "href": "href:28", + "id": "id:29", + "name": "acl2", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "action": "allow", + "before": { + "href": "href:99", + "id": "id:100", + "name": "acl2-out-2" + }, + "created_at": "2024-09-09T09:10:15.000Z", + "destination": "0.0.0.0/0", + "direction": "outbound", + "href": "href:97", + "id": "id:98", + "ip_version": "ipv4", + "name": "acl2-out-1", + "source": "10.240.20.0/24", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:101", + "id": "id:102", + "name": "acl2-in-1" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.10.0/24", + "direction": "outbound", + "href": "href:99", + "id": "id:100", + "ip_version": "ipv4", + "name": "acl2-out-2", + "source": "10.240.20.0/24", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:103", + "id": "id:104", + "name": "acl2-in-2" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.20.0/24", + "direction": "inbound", + "href": "href:101", + "id": "id:102", + "ip_version": "ipv4", + "name": "acl2-in-1", + "source": "0.0.0.0/0", + "protocol": "all" + }, + { + "action": "allow", + "created_at": "2024-09-09T09:10:17.000Z", + "destination": "10.240.20.0/24", + "direction": "inbound", + "href": "href:103", + "id": "id:104", + "ip_version": "ipv4", + "name": "acl2-in-2", + "source": "10.240.10.0/24", + "protocol": "all" + } + ], + "subnets": [ + { + "crn": "crn:24", + "href": "href:25", + "id": "id:26", + "name": "subnet2", + "resource_type": "subnet" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": "2024-09-09T09:10:14.000Z", + "crn": "crn:50", + "href": "href:51", + "id": "id:52", + "name": "acl1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "action": "allow", + "before": { + "href": "href:107", + "id": "id:108", + "name": "acl1-out-2" + }, + "created_at": "2024-09-09T09:10:15.000Z", + "destination": "172.217.22.46/32", + "direction": "outbound", + "href": "href:105", + "id": "id:106", + "ip_version": "ipv4", + "name": "acl1-out-1", + "source": "10.240.10.0/24", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:109", + "id": "id:110", + "name": "acl1-out-3" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.20.0/24", + "direction": "outbound", + "href": "href:107", + "id": "id:108", + "ip_version": "ipv4", + "name": "acl1-out-2", + "source": "10.240.10.0/24", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:111", + "id": "id:112", + "name": "acl1-out-4" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.30.0/24", + "direction": "outbound", + "href": "href:109", + "id": "id:110", + "ip_version": "ipv4", + "name": "acl1-out-3", + "source": "10.240.10.0/24", + "destination_port_max": 443, + "destination_port_min": 443, + "protocol": "tcp", + "source_port_max": 65535, + "source_port_min": 1 + }, + { + "action": "allow", + "before": { + "href": "href:113", + "id": "id:114", + "name": "acl1-in-1" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.30.0/24", + "direction": "outbound", + "href": "href:111", + "id": "id:112", + "ip_version": "ipv4", + "name": "acl1-out-4", + "source": "10.240.10.0/24", + "destination_port_max": 65535, + "destination_port_min": 1, + "protocol": "tcp", + "source_port_max": 443, + "source_port_min": 443 + }, + { + "action": "allow", + "before": { + "href": "href:115", + "id": "id:116", + "name": "acl1-in-2" + }, + "created_at": "2024-09-09T09:10:17.000Z", + "destination": "10.240.10.0/24", + "direction": "inbound", + "href": "href:113", + "id": "id:114", + "ip_version": "ipv4", + "name": "acl1-in-1", + "source": "172.217.22.46/32", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:117", + "id": "id:118", + "name": "acl1-in-3" + }, + "created_at": "2024-09-09T09:10:17.000Z", + "destination": "10.240.10.0/24", + "direction": "inbound", + "href": "href:115", + "id": "id:116", + "ip_version": "ipv4", + "name": "acl1-in-2", + "source": "10.240.20.0/24", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:119", + "id": "id:120", + "name": "acl1-in-4" + }, + "created_at": "2024-09-09T09:10:18.000Z", + "destination": "10.240.10.0/24", + "direction": "inbound", + "href": "href:117", + "id": "id:118", + "ip_version": "ipv4", + "name": "acl1-in-3", + "source": "10.240.30.0/24", + "destination_port_max": 65535, + "destination_port_min": 1, + "protocol": "tcp", + "source_port_max": 443, + "source_port_min": 443 + }, + { + "action": "allow", + "created_at": "2024-09-09T09:10:18.000Z", + "destination": "10.240.10.0/24", + "direction": "inbound", + "href": "href:119", + "id": "id:120", + "ip_version": "ipv4", + "name": "acl1-in-4", + "source": "10.240.30.0/24", + "destination_port_max": 443, + "destination_port_min": 443, + "protocol": "tcp", + "source_port_max": 65535, + "source_port_min": 1 + } + ], + "subnets": [ + { + "crn": "crn:47", + "href": "href:48", + "id": "id:49", + "name": "subnet1", + "resource_type": "subnet" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": "2024-09-09T09:10:14.000Z", + "crn": "crn:70", + "href": "href:71", + "id": "id:72", + "name": "acl3", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "action": "allow", + "before": { + "href": "href:123", + "id": "id:124", + "name": "acl3-out-2" + }, + "created_at": "2024-09-09T09:10:15.000Z", + "destination": "10.240.10.0/24", + "direction": "outbound", + "href": "href:121", + "id": "id:122", + "ip_version": "ipv4", + "name": "acl3-out-1", + "source": "10.240.30.0/24", + "destination_port_max": 443, + "destination_port_min": 443, + "protocol": "tcp", + "source_port_max": 65535, + "source_port_min": 1 + }, + { + "action": "allow", + "before": { + "href": "href:125", + "id": "id:126", + "name": "acl3-in-1" + }, + "created_at": "2024-09-09T09:10:15.000Z", + "destination": "10.240.10.0/24", + "direction": "outbound", + "href": "href:123", + "id": "id:124", + "ip_version": "ipv4", + "name": "acl3-out-2", + "source": "10.240.30.0/24", + "destination_port_max": 65535, + "destination_port_min": 1, + "protocol": "tcp", + "source_port_max": 443, + "source_port_min": 443 + }, + { + "action": "allow", + "before": { + "href": "href:127", + "id": "id:128", + "name": "acl3-in-2" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.30.0/24", + "direction": "inbound", + "href": "href:125", + "id": "id:126", + "ip_version": "ipv4", + "name": "acl3-in-1", + "source": "10.240.10.0/24", + "destination_port_max": 443, + "destination_port_min": 443, + "protocol": "tcp", + "source_port_max": 65535, + "source_port_min": 1 + }, + { + "action": "allow", + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.30.0/24", + "direction": "inbound", + "href": "href:127", + "id": "id:128", + "ip_version": "ipv4", + "name": "acl3-in-2", + "source": "10.240.10.0/24", + "destination_port_max": 65535, + "destination_port_min": 1, + "protocol": "tcp", + "source_port_max": 443, + "source_port_min": 443 + } + ], + "subnets": [ + { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": "2024-09-09T09:09:50.000Z", + "crn": "crn:8", + "href": "href:9", + "id": "id:10", + "name": "capitol-siren-chirpy-doornail", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "action": "allow", + "before": { + "href": "href:131", + "id": "id:132", + "name": "allow-outbound" + }, + "created_at": "2024-09-09T09:09:50.000Z", + "destination": "0.0.0.0/0", + "direction": "inbound", + "href": "href:129", + "id": "id:130", + "ip_version": "ipv4", + "name": "allow-inbound", + "source": "0.0.0.0/0", + "protocol": "all" + }, + { + "action": "allow", + "created_at": "2024-09-09T09:09:50.000Z", + "destination": "0.0.0.0/0", + "direction": "outbound", + "href": "href:131", + "id": "id:132", + "ip_version": "ipv4", + "name": "allow-outbound", + "source": "0.0.0.0/0", + "protocol": "all" + } + ], + "subnets": [], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + } + ], + "security_groups": [ + { + "created_at": "2024-09-09T09:10:14.000Z", + "crn": "crn:133", + "href": "href:134", + "id": "id:135", + "name": "sg1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "direction": "inbound", + "href": "href:136", + "id": "id:137", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.0/0" + }, + "protocol": "all" + }, + { + "direction": "outbound", + "href": "href:138", + "id": "id:139", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.0/0" + }, + "protocol": "all" + } + ], + "targets": [], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": "2024-09-09T09:09:50.000Z", + "crn": "crn:13", + "href": "href:14", + "id": "id:15", + "name": "wombat-hesitate-scorn-subprime", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "direction": "outbound", + "href": "href:140", + "id": "id:141", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.0/0" + }, + "protocol": "all" + }, + { + "direction": "inbound", + "href": "href:142", + "id": "id:143", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "crn": "crn:13", + "href": "href:14", + "id": "id:15", + "name": "wombat-hesitate-scorn-subprime" + }, + "protocol": "all" + } + ], + "targets": [], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": null, + "crn": "fake:crn:3", + "href": "fake:href:3", + "id": "fake:id:3", + "name": "test-vpc1--vsi2", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "direction": "inbound", + "href": "fake:href:1", + "id": "fake:id:1", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "crn": "fake:crn:2", + "href": "fake:href:2", + "id": "fake:id:2", + "name": "test-vpc1--vsi1" + }, + "protocol": "all" + } + ], + "targets": [ + { + "href": "href:43", + "id": "id:44", + "name": "ni2", + "resource_type": "network_interface" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": null, + "crn": "fake:crn:2", + "href": "fake:href:2", + "id": "fake:id:2", + "name": "test-vpc1--vsi1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "direction": "outbound", + "href": "fake:href:4", + "id": "fake:id:4", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.0/30" + }, + "protocol": "all" + }, + { + "direction": "outbound", + "href": "fake:href:5", + "id": "fake:id:5", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.0/31" + }, + "protocol": "all" + }, + { + "direction": "outbound", + "href": "fake:href:6", + "id": "fake:id:6", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "crn": "fake:crn:3", + "href": "fake:href:3", + "id": "fake:id:3", + "name": "test-vpc1--vsi2" + }, + "protocol": "all" + } + ], + "targets": [ + { + "href": "href:63", + "id": "id:64", + "name": "ni1", + "resource_type": "network_interface" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": null, + "crn": "fake:crn:7", + "href": "fake:href:7", + "id": "fake:id:7", + "name": "test-vpc1--vsi3b", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [], + "targets": [ + { + "href": "href:87", + "id": "id:88", + "name": "ni3b", + "resource_type": "network_interface" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": null, + "crn": "fake:crn:8", + "href": "fake:href:8", + "id": "fake:id:8", + "name": "test-vpc1--vsi3a", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [], + "targets": [ + { + "href": "href:83", + "id": "id:84", + "name": "ni3a", + "resource_type": "network_interface" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + } + ], + "endpoint_gateways": [], + "instances": [ + { + "availability_policy": { + "host_failure": "restart" + }, + "bandwidth": 4000, + "boot_volume_attachment": { + "device": { + "id": "id:149" + }, + "href": "href:147", + "id": "id:148", + "name": "falsetto-snowstorm-bankbook-agreement", + "volume": { + "crn": "crn:150", + "href": "href:151", + "id": "id:152", + "name": "prawn-trusting-pasty-dental", + "resource_type": "volume" + } + }, + "confidential_compute_mode": "disabled", + "created_at": "2024-09-09T09:11:07.000Z", + "crn": "crn:144", + "disks": [], + "enable_secure_boot": false, + "health_reasons": [], + "health_state": "ok", + "href": "href:145", + "id": "id:146", + "image": { + "crn": "crn:153", + "href": "href:154", + "id": "id:155", + "name": "server-9080", + "resource_type": "image" + }, + "lifecycle_reasons": [], + "lifecycle_state": "stable", + "memory": 4, + "metadata_service": { + "enabled": false, + "protocol": "http", + "response_hop_limit": 1 + }, + "name": "vsi2", + "network_attachments": [], + "numa_count": 1, + "primary_network_interface": { + "href": "href:43", + "id": "id:44", + "name": "ni2", + "primary_ip": { + "address": "10.240.20.4", + "href": "href:41", + "id": "id:42", + "name": "startle-percent-embellish-squeegee", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "subnet": { + "crn": "crn:24", + "href": "href:25", + "id": "id:26", + "name": "subnet2", + "resource_type": "subnet" + } + }, + "profile": { + "href": "href:156", + "name": "cx2-2x4", + "resource_type": "instance_profile" + }, + "reservation_affinity": { + "policy": "disabled", + "pool": [] + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "instance", + "startable": true, + "status": "running", + "status_reasons": [], + "total_network_bandwidth": 3000, + "total_volume_bandwidth": 1000, + "vcpu": { + "architecture": "amd64", + "count": 2, + "manufacturer": "intel" + }, + "volume_attachments": [ + { + "device": { + "id": "id:149" + }, + "href": "href:147", + "id": "id:148", + "name": "falsetto-snowstorm-bankbook-agreement", + "volume": { + "crn": "crn:150", + "href": "href:151", + "id": "id:152", + "name": "prawn-trusting-pasty-dental", + "resource_type": "volume" + } + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "network_interfaces": [ + { + "allow_ip_spoofing": false, + "created_at": "2024-09-09T09:11:07.000Z", + "floating_ips": [], + "href": "href:43", + "id": "id:44", + "name": "ni2", + "port_speed": 3000, + "primary_ip": { + "address": "10.240.20.4", + "href": "href:41", + "id": "id:42", + "name": "startle-percent-embellish-squeegee", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "security_groups": [ + { + "crn": "fake:crn:3", + "href": "fake:href:3", + "id": "fake:id:3", + "name": "test-vpc1--vsi2" + } + ], + "status": "available", + "subnet": { + "crn": "crn:24", + "href": "href:25", + "id": "id:26", + "name": "subnet2", + "resource_type": "subnet" + }, + "type": "primary" + } + ], + "tags": [] + }, + { + "availability_policy": { + "host_failure": "restart" + }, + "bandwidth": 4000, + "boot_volume_attachment": { + "device": { + "id": "id:162" + }, + "href": "href:160", + "id": "id:161", + "name": "outskirts-oversized-roundish-ludicrous", + "volume": { + "crn": "crn:163", + "href": "href:164", + "id": "id:165", + "name": "family-tackling-foothold-train", + "resource_type": "volume" + } + }, + "confidential_compute_mode": "disabled", + "created_at": "2024-09-09T09:10:52.000Z", + "crn": "crn:157", + "disks": [], + "enable_secure_boot": false, + "health_reasons": [], + "health_state": "ok", + "href": "href:158", + "id": "id:159", + "image": { + "crn": "crn:153", + "href": "href:154", + "id": "id:155", + "name": "server-9080", + "resource_type": "image" + }, + "lifecycle_reasons": [], + "lifecycle_state": "stable", + "memory": 4, + "metadata_service": { + "enabled": false, + "protocol": "http", + "response_hop_limit": 1 + }, + "name": "vsi1", + "network_attachments": [], + "numa_count": 1, + "primary_network_interface": { + "href": "href:63", + "id": "id:64", + "name": "ni1", + "primary_ip": { + "address": "10.240.10.4", + "href": "href:61", + "id": "id:62", + "name": "tableware-sprawl-shrivel-popper", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "subnet": { + "crn": "crn:47", + "href": "href:48", + "id": "id:49", + "name": "subnet1", + "resource_type": "subnet" + } + }, + "profile": { + "href": "href:156", + "name": "cx2-2x4", + "resource_type": "instance_profile" + }, + "reservation_affinity": { + "policy": "disabled", + "pool": [] + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "instance", + "startable": true, + "status": "running", + "status_reasons": [], + "total_network_bandwidth": 3000, + "total_volume_bandwidth": 1000, + "vcpu": { + "architecture": "amd64", + "count": 2, + "manufacturer": "intel" + }, + "volume_attachments": [ + { + "device": { + "id": "id:162" + }, + "href": "href:160", + "id": "id:161", + "name": "outskirts-oversized-roundish-ludicrous", + "volume": { + "crn": "crn:163", + "href": "href:164", + "id": "id:165", + "name": "family-tackling-foothold-train", + "resource_type": "volume" + } + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "network_interfaces": [ + { + "allow_ip_spoofing": false, + "created_at": "2024-09-09T09:10:52.000Z", + "floating_ips": [ + { + "address": "52.116.129.168", + "crn": "crn:94", + "href": "href:95", + "id": "id:96", + "name": "vsi1-fip" + } + ], + "href": "href:63", + "id": "id:64", + "name": "ni1", + "port_speed": 3000, + "primary_ip": { + "address": "10.240.10.4", + "href": "href:61", + "id": "id:62", + "name": "tableware-sprawl-shrivel-popper", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "security_groups": [ + { + "crn": "fake:crn:2", + "href": "fake:href:2", + "id": "fake:id:2", + "name": "test-vpc1--vsi1" + } + ], + "status": "available", + "subnet": { + "crn": "crn:47", + "href": "href:48", + "id": "id:49", + "name": "subnet1", + "resource_type": "subnet" + }, + "type": "primary" + } + ], + "tags": [] + }, + { + "availability_policy": { + "host_failure": "restart" + }, + "bandwidth": 4000, + "boot_volume_attachment": { + "device": { + "id": "id:171" + }, + "href": "href:169", + "id": "id:170", + "name": "camera-yam-headfirst-scabiosa", + "volume": { + "crn": "crn:172", + "href": "href:173", + "id": "id:174", + "name": "sprinkler-avenue-playset-dislodge", + "resource_type": "volume" + } + }, + "confidential_compute_mode": "disabled", + "created_at": "2024-09-09T09:10:35.000Z", + "crn": "crn:166", + "disks": [], + "enable_secure_boot": false, + "health_reasons": [], + "health_state": "ok", + "href": "href:167", + "id": "id:168", + "image": { + "crn": "crn:153", + "href": "href:154", + "id": "id:155", + "name": "server-9080", + "resource_type": "image" + }, + "lifecycle_reasons": [], + "lifecycle_state": "stable", + "memory": 4, + "metadata_service": { + "enabled": false, + "protocol": "http", + "response_hop_limit": 1 + }, + "name": "vsi3b", + "network_attachments": [], + "numa_count": 1, + "primary_network_interface": { + "href": "href:87", + "id": "id:88", + "name": "ni3b", + "primary_ip": { + "address": "10.240.30.5", + "href": "href:85", + "id": "id:86", + "name": "reheat-joyride-little-overprice", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "subnet": { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + } + }, + "profile": { + "href": "href:156", + "name": "cx2-2x4", + "resource_type": "instance_profile" + }, + "reservation_affinity": { + "policy": "disabled", + "pool": [] + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "instance", + "startable": true, + "status": "running", + "status_reasons": [], + "total_network_bandwidth": 3000, + "total_volume_bandwidth": 1000, + "vcpu": { + "architecture": "amd64", + "count": 2, + "manufacturer": "intel" + }, + "volume_attachments": [ + { + "device": { + "id": "id:171" + }, + "href": "href:169", + "id": "id:170", + "name": "camera-yam-headfirst-scabiosa", + "volume": { + "crn": "crn:172", + "href": "href:173", + "id": "id:174", + "name": "sprinkler-avenue-playset-dislodge", + "resource_type": "volume" + } + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "network_interfaces": [ + { + "allow_ip_spoofing": false, + "created_at": "2024-09-09T09:10:34.000Z", + "floating_ips": [], + "href": "href:87", + "id": "id:88", + "name": "ni3b", + "port_speed": 3000, + "primary_ip": { + "address": "10.240.30.5", + "href": "href:85", + "id": "id:86", + "name": "reheat-joyride-little-overprice", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "security_groups": [ + { + "crn": "fake:crn:7", + "href": "fake:href:7", + "id": "fake:id:7", + "name": "test-vpc1--vsi3b" + } + ], + "status": "available", + "subnet": { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + }, + "type": "primary" + } + ], + "tags": [] + }, + { + "availability_policy": { + "host_failure": "restart" + }, + "bandwidth": 4000, + "boot_volume_attachment": { + "device": { + "id": "id:180" + }, + "href": "href:178", + "id": "id:179", + "name": "cryptic-cork-saponify-lively", + "volume": { + "crn": "crn:181", + "href": "href:182", + "id": "id:183", + "name": "appraisal-mountains-itinerary-twine", + "resource_type": "volume" + } + }, + "confidential_compute_mode": "disabled", + "created_at": "2024-09-09T09:10:34.000Z", + "crn": "crn:175", + "disks": [], + "enable_secure_boot": false, + "health_reasons": [], + "health_state": "ok", + "href": "href:176", + "id": "id:177", + "image": { + "crn": "crn:153", + "href": "href:154", + "id": "id:155", + "name": "server-9080", + "resource_type": "image" + }, + "lifecycle_reasons": [], + "lifecycle_state": "stable", + "memory": 4, + "metadata_service": { + "enabled": false, + "protocol": "http", + "response_hop_limit": 1 + }, + "name": "vsi3a", + "network_attachments": [], + "numa_count": 1, + "primary_network_interface": { + "href": "href:83", + "id": "id:84", + "name": "ni3a", + "primary_ip": { + "address": "10.240.30.4", + "href": "href:81", + "id": "id:82", + "name": "disallow-oxidant-etching-selection", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "subnet": { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + } + }, + "profile": { + "href": "href:156", + "name": "cx2-2x4", + "resource_type": "instance_profile" + }, + "reservation_affinity": { + "policy": "disabled", + "pool": [] + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "instance", + "startable": true, + "status": "running", + "status_reasons": [], + "total_network_bandwidth": 3000, + "total_volume_bandwidth": 1000, + "vcpu": { + "architecture": "amd64", + "count": 2, + "manufacturer": "intel" + }, + "volume_attachments": [ + { + "device": { + "id": "id:180" + }, + "href": "href:178", + "id": "id:179", + "name": "cryptic-cork-saponify-lively", + "volume": { + "crn": "crn:181", + "href": "href:182", + "id": "id:183", + "name": "appraisal-mountains-itinerary-twine", + "resource_type": "volume" + } + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "network_interfaces": [ + { + "allow_ip_spoofing": false, + "created_at": "2024-09-09T09:10:34.000Z", + "floating_ips": [], + "href": "href:83", + "id": "id:84", + "name": "ni3a", + "port_speed": 3000, + "primary_ip": { + "address": "10.240.30.4", + "href": "href:81", + "id": "id:82", + "name": "disallow-oxidant-etching-selection", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "security_groups": [ + { + "crn": "fake:crn:8", + "href": "fake:href:8", + "id": "fake:id:8", + "name": "test-vpc1--vsi3a" + } + ], + "status": "available", + "subnet": { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + }, + "type": "primary" + } + ], + "tags": [] + } + ], + "virtual_nis": null, + "routing_tables": [ + { + "accept_routes_from": [ + { + "resource_type": "vpn_gateway" + }, + { + "resource_type": "vpn_server" + } + ], + "advertise_routes_to": [], + "created_at": "2024-09-09T09:09:51.000Z", + "href": "href:11", + "id": "id:12", + "is_default": true, + "lifecycle_state": "stable", + "name": "fiscally-fresh-uncanny-ceramics", + "resource_type": "routing_table", + "route_direct_link_ingress": false, + "route_internet_ingress": false, + "route_transit_gateway_ingress": false, + "route_vpc_zone_ingress": false, + "subnets": [ + { + "crn": "crn:24", + "href": "href:25", + "id": "id:26", + "name": "subnet2", + "resource_type": "subnet" + }, + { + "crn": "crn:47", + "href": "href:48", + "id": "id:49", + "name": "subnet1", + "resource_type": "subnet" + }, + { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + } + ], + "routes": [], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + } + } + ], + "load_balancers": [], + "transit_connections": null, + "transit_gateways": null, + "iks_clusters": [] +} \ No newline at end of file diff --git a/test/data/optimize_sg_redundant/conn_spec.json b/test/data/optimize_sg_redundant/conn_spec.json new file mode 100644 index 00000000..ef2331cd --- /dev/null +++ b/test/data/optimize_sg_redundant/conn_spec.json @@ -0,0 +1,48 @@ +{ + "externals": { + "e1": "0.0.0.0/30", + "e2": "0.0.0.0/31" + }, + "required-connections": [ + { + "src": { + "name": "vsi1", + "type": "instance" + }, + "dst": { + "name": "e1", + "type": "external" + } + }, + { + "src": { + "name": "vsi1", + "type": "instance" + }, + "dst": { + "name": "e2", + "type": "external" + } + }, + { + "src": { + "name": "vsi1", + "type": "instance" + }, + "dst": { + "name": "vsi2", + "type": "instance" + } + }, + { + "src": { + "name": "vsi1", + "type": "instance" + }, + "dst": { + "name": "vsi2", + "type": "instance" + } + } + ] +} diff --git a/test/data/optimize_sg_redundant/details.txt b/test/data/optimize_sg_redundant/details.txt new file mode 100644 index 00000000..70573b2d --- /dev/null +++ b/test/data/optimize_sg_redundant/details.txt @@ -0,0 +1,10 @@ +vsi1 --> 0.0.0.0/30 (protocol all) +vsi1 --> 0.0.0.0/31 (protocol all) + +vsi1 --> vsi2 (protocol all) +vsi1 --> vsi2 (protocol all) + +==================================== + +vsi1 --> 0.0.0.0/30 (all protocol) +vsi1 --> vsi2 (all protocol) \ No newline at end of file diff --git a/test/data/optimize_sg_t/config_object.json b/test/data/optimize_sg_t/config_object.json new file mode 100644 index 00000000..347bd139 --- /dev/null +++ b/test/data/optimize_sg_t/config_object.json @@ -0,0 +1,2009 @@ +{ + "collector_version": "0.11.0", + "provider": "ibm", + "vpcs": [ + { + "classic_access": false, + "created_at": "2024-09-09T09:09:50.000Z", + "crn": "crn:1", + "cse_source_ips": [ + { + "ip": { + "address": "10.22.217.112" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + } + }, + { + "ip": { + "address": "10.12.160.153" + }, + "zone": { + "href": "href:6", + "name": "us-south-2" + } + }, + { + "ip": { + "address": "10.16.253.223" + }, + "zone": { + "href": "href:7", + "name": "us-south-3" + } + } + ], + "default_network_acl": { + "crn": "crn:8", + "href": "href:9", + "id": "id:10", + "name": "capitol-siren-chirpy-doornail" + }, + "default_routing_table": { + "href": "href:11", + "id": "id:12", + "name": "fiscally-fresh-uncanny-ceramics", + "resource_type": "routing_table" + }, + "default_security_group": { + "crn": "crn:13", + "href": "href:14", + "id": "id:15", + "name": "wombat-hesitate-scorn-subprime" + }, + "dns": { + "enable_hub": false, + "resolution_binding_count": 0, + "resolver": { + "servers": [ + { + "address": "161.26.0.10" + }, + { + "address": "161.26.0.11" + } + ], + "type": "system", + "configuration": "default" + } + }, + "health_reasons": null, + "health_state": "ok", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "vpc", + "status": "available", + "region": "us-south", + "address_prefixes": [ + { + "cidr": "10.240.0.0/18", + "created_at": "2024-09-09T09:09:50.000Z", + "has_subnets": true, + "href": "href:18", + "id": "id:19", + "is_default": true, + "name": "filling-tasty-bacterium-parlor", + "zone": { + "href": "href:5", + "name": "us-south-1" + } + }, + { + "cidr": "10.240.64.0/18", + "created_at": "2024-09-09T09:09:50.000Z", + "has_subnets": false, + "href": "href:20", + "id": "id:21", + "is_default": true, + "name": "relearn-ragweed-goon-feisty", + "zone": { + "href": "href:6", + "name": "us-south-2" + } + }, + { + "cidr": "10.240.128.0/18", + "created_at": "2024-09-09T09:09:50.000Z", + "has_subnets": false, + "href": "href:22", + "id": "id:23", + "is_default": true, + "name": "unruffled-penknife-snowshoe-ninetieth", + "zone": { + "href": "href:7", + "name": "us-south-3" + } + } + ], + "tags": [] + } + ], + "subnets": [ + { + "available_ipv4_address_count": 250, + "created_at": "2024-09-09T09:10:51.000Z", + "crn": "crn:24", + "href": "href:25", + "id": "id:26", + "ip_version": "ipv4", + "ipv4_cidr_block": "10.240.20.0/24", + "name": "subnet2", + "network_acl": { + "crn": "crn:27", + "href": "href:28", + "id": "id:29", + "name": "acl2" + }, + "public_gateway": { + "crn": "crn:30", + "href": "href:31", + "id": "id:32", + "name": "public-gw1", + "resource_type": "public_gateway" + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "subnet", + "routing_table": { + "href": "href:11", + "id": "id:12", + "name": "fiscally-fresh-uncanny-ceramics", + "resource_type": "routing_table" + }, + "status": "available", + "total_ipv4_address_count": 256, + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "reserved_ips": [ + { + "address": "10.240.20.0", + "auto_delete": false, + "created_at": "2024-09-09T09:10:51.000Z", + "href": "href:33", + "id": "id:34", + "lifecycle_state": "stable", + "name": "ibm-network-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.20.1", + "auto_delete": false, + "created_at": "2024-09-09T09:10:51.000Z", + "href": "href:35", + "id": "id:36", + "lifecycle_state": "stable", + "name": "ibm-default-gateway", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.20.2", + "auto_delete": false, + "created_at": "2024-09-09T09:10:51.000Z", + "href": "href:37", + "id": "id:38", + "lifecycle_state": "stable", + "name": "ibm-dns-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.20.3", + "auto_delete": false, + "created_at": "2024-09-09T09:10:51.000Z", + "href": "href:39", + "id": "id:40", + "lifecycle_state": "stable", + "name": "ibm-reserved-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.20.4", + "auto_delete": true, + "created_at": "2024-09-09T09:11:08.000Z", + "href": "href:41", + "id": "id:42", + "lifecycle_state": "stable", + "name": "startle-percent-embellish-squeegee", + "owner": "user", + "resource_type": "subnet_reserved_ip", + "target": { + "href": "href:43", + "id": "id:44", + "name": "ni2", + "resource_type": "network_interface" + } + }, + { + "address": "10.240.20.255", + "auto_delete": false, + "created_at": "2024-09-09T09:10:51.000Z", + "href": "href:45", + "id": "id:46", + "lifecycle_state": "stable", + "name": "ibm-broadcast-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + } + ], + "tags": [] + }, + { + "available_ipv4_address_count": 250, + "created_at": "2024-09-09T09:10:35.000Z", + "crn": "crn:47", + "href": "href:48", + "id": "id:49", + "ip_version": "ipv4", + "ipv4_cidr_block": "10.240.10.0/24", + "name": "subnet1", + "network_acl": { + "crn": "crn:50", + "href": "href:51", + "id": "id:52", + "name": "acl1" + }, + "public_gateway": { + "crn": "crn:30", + "href": "href:31", + "id": "id:32", + "name": "public-gw1", + "resource_type": "public_gateway" + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "subnet", + "routing_table": { + "href": "href:11", + "id": "id:12", + "name": "fiscally-fresh-uncanny-ceramics", + "resource_type": "routing_table" + }, + "status": "available", + "total_ipv4_address_count": 256, + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "reserved_ips": [ + { + "address": "10.240.10.0", + "auto_delete": false, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:53", + "id": "id:54", + "lifecycle_state": "stable", + "name": "ibm-network-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.10.1", + "auto_delete": false, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:55", + "id": "id:56", + "lifecycle_state": "stable", + "name": "ibm-default-gateway", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.10.2", + "auto_delete": false, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:57", + "id": "id:58", + "lifecycle_state": "stable", + "name": "ibm-dns-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.10.3", + "auto_delete": false, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:59", + "id": "id:60", + "lifecycle_state": "stable", + "name": "ibm-reserved-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.10.4", + "auto_delete": true, + "created_at": "2024-09-09T09:10:52.000Z", + "href": "href:61", + "id": "id:62", + "lifecycle_state": "stable", + "name": "tableware-sprawl-shrivel-popper", + "owner": "user", + "resource_type": "subnet_reserved_ip", + "target": { + "href": "href:63", + "id": "id:64", + "name": "ni1", + "resource_type": "network_interface" + } + }, + { + "address": "10.240.10.255", + "auto_delete": false, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:65", + "id": "id:66", + "lifecycle_state": "stable", + "name": "ibm-broadcast-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + } + ], + "tags": [] + }, + { + "available_ipv4_address_count": 249, + "created_at": "2024-09-09T09:10:18.000Z", + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "ip_version": "ipv4", + "ipv4_cidr_block": "10.240.30.0/24", + "name": "subnet3", + "network_acl": { + "crn": "crn:70", + "href": "href:71", + "id": "id:72", + "name": "acl3" + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "subnet", + "routing_table": { + "href": "href:11", + "id": "id:12", + "name": "fiscally-fresh-uncanny-ceramics", + "resource_type": "routing_table" + }, + "status": "available", + "total_ipv4_address_count": 256, + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "reserved_ips": [ + { + "address": "10.240.30.0", + "auto_delete": false, + "created_at": "2024-09-09T09:10:18.000Z", + "href": "href:73", + "id": "id:74", + "lifecycle_state": "stable", + "name": "ibm-network-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.30.1", + "auto_delete": false, + "created_at": "2024-09-09T09:10:18.000Z", + "href": "href:75", + "id": "id:76", + "lifecycle_state": "stable", + "name": "ibm-default-gateway", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.30.2", + "auto_delete": false, + "created_at": "2024-09-09T09:10:18.000Z", + "href": "href:77", + "id": "id:78", + "lifecycle_state": "stable", + "name": "ibm-dns-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.30.3", + "auto_delete": false, + "created_at": "2024-09-09T09:10:18.000Z", + "href": "href:79", + "id": "id:80", + "lifecycle_state": "stable", + "name": "ibm-reserved-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.30.4", + "auto_delete": true, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:81", + "id": "id:82", + "lifecycle_state": "stable", + "name": "disallow-oxidant-etching-selection", + "owner": "user", + "resource_type": "subnet_reserved_ip", + "target": { + "href": "href:83", + "id": "id:84", + "name": "ni3a", + "resource_type": "network_interface" + } + }, + { + "address": "10.240.30.5", + "auto_delete": true, + "created_at": "2024-09-09T09:10:36.000Z", + "href": "href:85", + "id": "id:86", + "lifecycle_state": "stable", + "name": "reheat-joyride-little-overprice", + "owner": "user", + "resource_type": "subnet_reserved_ip", + "target": { + "href": "href:87", + "id": "id:88", + "name": "ni3b", + "resource_type": "network_interface" + } + }, + { + "address": "10.240.30.255", + "auto_delete": false, + "created_at": "2024-09-09T09:10:18.000Z", + "href": "href:89", + "id": "id:90", + "lifecycle_state": "stable", + "name": "ibm-broadcast-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + } + ], + "tags": [] + } + ], + "public_gateways": [ + { + "created_at": "2024-09-09T09:10:14.000Z", + "crn": "crn:30", + "floating_ip": { + "address": "52.118.147.142", + "crn": "crn:91", + "href": "href:92", + "id": "id:93", + "name": "public-gw1" + }, + "href": "href:31", + "id": "id:32", + "name": "public-gw1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "public_gateway", + "status": "available", + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "tags": [] + } + ], + "floating_ips": [ + { + "address": "52.116.129.168", + "created_at": "2024-09-09T09:11:31.000Z", + "crn": "crn:94", + "href": "href:95", + "id": "id:96", + "name": "vsi1-fip", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "status": "available", + "target": { + "href": "href:63", + "id": "id:64", + "name": "ni1", + "primary_ip": { + "address": "10.240.10.4", + "href": "href:61", + "id": "id:62", + "name": "tableware-sprawl-shrivel-popper", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "tags": [] + }, + { + "address": "52.118.147.142", + "created_at": "2024-09-09T09:10:14.000Z", + "crn": "crn:91", + "href": "href:92", + "id": "id:93", + "name": "public-gw1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "status": "available", + "target": { + "href": "href:31", + "id": "id:32", + "name": "public-gw1", + "resource_type": "public_gateway", + "crn": "crn:30" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "tags": [] + } + ], + "network_acls": [ + { + "created_at": "2024-09-09T09:10:15.000Z", + "crn": "crn:27", + "href": "href:28", + "id": "id:29", + "name": "acl2", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "action": "allow", + "before": { + "href": "href:99", + "id": "id:100", + "name": "acl2-out-2" + }, + "created_at": "2024-09-09T09:10:15.000Z", + "destination": "0.0.0.0/0", + "direction": "outbound", + "href": "href:97", + "id": "id:98", + "ip_version": "ipv4", + "name": "acl2-out-1", + "source": "10.240.20.0/24", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:101", + "id": "id:102", + "name": "acl2-in-1" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.10.0/24", + "direction": "outbound", + "href": "href:99", + "id": "id:100", + "ip_version": "ipv4", + "name": "acl2-out-2", + "source": "10.240.20.0/24", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:103", + "id": "id:104", + "name": "acl2-in-2" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.20.0/24", + "direction": "inbound", + "href": "href:101", + "id": "id:102", + "ip_version": "ipv4", + "name": "acl2-in-1", + "source": "0.0.0.0/0", + "protocol": "all" + }, + { + "action": "allow", + "created_at": "2024-09-09T09:10:17.000Z", + "destination": "10.240.20.0/24", + "direction": "inbound", + "href": "href:103", + "id": "id:104", + "ip_version": "ipv4", + "name": "acl2-in-2", + "source": "10.240.10.0/24", + "protocol": "all" + } + ], + "subnets": [ + { + "crn": "crn:24", + "href": "href:25", + "id": "id:26", + "name": "subnet2", + "resource_type": "subnet" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": "2024-09-09T09:10:14.000Z", + "crn": "crn:50", + "href": "href:51", + "id": "id:52", + "name": "acl1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "action": "allow", + "before": { + "href": "href:107", + "id": "id:108", + "name": "acl1-out-2" + }, + "created_at": "2024-09-09T09:10:15.000Z", + "destination": "172.217.22.46/32", + "direction": "outbound", + "href": "href:105", + "id": "id:106", + "ip_version": "ipv4", + "name": "acl1-out-1", + "source": "10.240.10.0/24", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:109", + "id": "id:110", + "name": "acl1-out-3" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.20.0/24", + "direction": "outbound", + "href": "href:107", + "id": "id:108", + "ip_version": "ipv4", + "name": "acl1-out-2", + "source": "10.240.10.0/24", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:111", + "id": "id:112", + "name": "acl1-out-4" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.30.0/24", + "direction": "outbound", + "href": "href:109", + "id": "id:110", + "ip_version": "ipv4", + "name": "acl1-out-3", + "source": "10.240.10.0/24", + "destination_port_max": 443, + "destination_port_min": 443, + "protocol": "tcp", + "source_port_max": 65535, + "source_port_min": 1 + }, + { + "action": "allow", + "before": { + "href": "href:113", + "id": "id:114", + "name": "acl1-in-1" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.30.0/24", + "direction": "outbound", + "href": "href:111", + "id": "id:112", + "ip_version": "ipv4", + "name": "acl1-out-4", + "source": "10.240.10.0/24", + "destination_port_max": 65535, + "destination_port_min": 1, + "protocol": "tcp", + "source_port_max": 443, + "source_port_min": 443 + }, + { + "action": "allow", + "before": { + "href": "href:115", + "id": "id:116", + "name": "acl1-in-2" + }, + "created_at": "2024-09-09T09:10:17.000Z", + "destination": "10.240.10.0/24", + "direction": "inbound", + "href": "href:113", + "id": "id:114", + "ip_version": "ipv4", + "name": "acl1-in-1", + "source": "172.217.22.46/32", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:117", + "id": "id:118", + "name": "acl1-in-3" + }, + "created_at": "2024-09-09T09:10:17.000Z", + "destination": "10.240.10.0/24", + "direction": "inbound", + "href": "href:115", + "id": "id:116", + "ip_version": "ipv4", + "name": "acl1-in-2", + "source": "10.240.20.0/24", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:119", + "id": "id:120", + "name": "acl1-in-4" + }, + "created_at": "2024-09-09T09:10:18.000Z", + "destination": "10.240.10.0/24", + "direction": "inbound", + "href": "href:117", + "id": "id:118", + "ip_version": "ipv4", + "name": "acl1-in-3", + "source": "10.240.30.0/24", + "destination_port_max": 65535, + "destination_port_min": 1, + "protocol": "tcp", + "source_port_max": 443, + "source_port_min": 443 + }, + { + "action": "allow", + "created_at": "2024-09-09T09:10:18.000Z", + "destination": "10.240.10.0/24", + "direction": "inbound", + "href": "href:119", + "id": "id:120", + "ip_version": "ipv4", + "name": "acl1-in-4", + "source": "10.240.30.0/24", + "destination_port_max": 443, + "destination_port_min": 443, + "protocol": "tcp", + "source_port_max": 65535, + "source_port_min": 1 + } + ], + "subnets": [ + { + "crn": "crn:47", + "href": "href:48", + "id": "id:49", + "name": "subnet1", + "resource_type": "subnet" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": "2024-09-09T09:10:14.000Z", + "crn": "crn:70", + "href": "href:71", + "id": "id:72", + "name": "acl3", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "action": "allow", + "before": { + "href": "href:123", + "id": "id:124", + "name": "acl3-out-2" + }, + "created_at": "2024-09-09T09:10:15.000Z", + "destination": "10.240.10.0/24", + "direction": "outbound", + "href": "href:121", + "id": "id:122", + "ip_version": "ipv4", + "name": "acl3-out-1", + "source": "10.240.30.0/24", + "destination_port_max": 443, + "destination_port_min": 443, + "protocol": "tcp", + "source_port_max": 65535, + "source_port_min": 1 + }, + { + "action": "allow", + "before": { + "href": "href:125", + "id": "id:126", + "name": "acl3-in-1" + }, + "created_at": "2024-09-09T09:10:15.000Z", + "destination": "10.240.10.0/24", + "direction": "outbound", + "href": "href:123", + "id": "id:124", + "ip_version": "ipv4", + "name": "acl3-out-2", + "source": "10.240.30.0/24", + "destination_port_max": 65535, + "destination_port_min": 1, + "protocol": "tcp", + "source_port_max": 443, + "source_port_min": 443 + }, + { + "action": "allow", + "before": { + "href": "href:127", + "id": "id:128", + "name": "acl3-in-2" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.30.0/24", + "direction": "inbound", + "href": "href:125", + "id": "id:126", + "ip_version": "ipv4", + "name": "acl3-in-1", + "source": "10.240.10.0/24", + "destination_port_max": 443, + "destination_port_min": 443, + "protocol": "tcp", + "source_port_max": 65535, + "source_port_min": 1 + }, + { + "action": "allow", + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.30.0/24", + "direction": "inbound", + "href": "href:127", + "id": "id:128", + "ip_version": "ipv4", + "name": "acl3-in-2", + "source": "10.240.10.0/24", + "destination_port_max": 65535, + "destination_port_min": 1, + "protocol": "tcp", + "source_port_max": 443, + "source_port_min": 443 + } + ], + "subnets": [ + { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": "2024-09-09T09:09:50.000Z", + "crn": "crn:8", + "href": "href:9", + "id": "id:10", + "name": "capitol-siren-chirpy-doornail", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "action": "allow", + "before": { + "href": "href:131", + "id": "id:132", + "name": "allow-outbound" + }, + "created_at": "2024-09-09T09:09:50.000Z", + "destination": "0.0.0.0/0", + "direction": "inbound", + "href": "href:129", + "id": "id:130", + "ip_version": "ipv4", + "name": "allow-inbound", + "source": "0.0.0.0/0", + "protocol": "all" + }, + { + "action": "allow", + "created_at": "2024-09-09T09:09:50.000Z", + "destination": "0.0.0.0/0", + "direction": "outbound", + "href": "href:131", + "id": "id:132", + "ip_version": "ipv4", + "name": "allow-outbound", + "source": "0.0.0.0/0", + "protocol": "all" + } + ], + "subnets": [], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + } + ], + "security_groups": [ + { + "created_at": "2024-09-09T09:10:14.000Z", + "crn": "crn:133", + "href": "href:134", + "id": "id:135", + "name": "sg1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "direction": "inbound", + "href": "href:136", + "id": "id:137", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.0/0" + }, + "protocol": "all" + }, + { + "direction": "outbound", + "href": "href:138", + "id": "id:139", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.0/0" + }, + "protocol": "all" + } + ], + "targets": [], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": "2024-09-09T09:09:50.000Z", + "crn": "crn:13", + "href": "href:14", + "id": "id:15", + "name": "wombat-hesitate-scorn-subprime", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "direction": "outbound", + "href": "href:140", + "id": "id:141", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.0/0" + }, + "protocol": "all" + }, + { + "direction": "inbound", + "href": "href:142", + "id": "id:143", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "crn": "crn:13", + "href": "href:14", + "id": "id:15", + "name": "wombat-hesitate-scorn-subprime" + }, + "protocol": "all" + } + ], + "targets": [], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": null, + "crn": "fake:crn:1", + "href": "fake:href:1", + "id": "fake:id:1", + "name": "test-vpc1--vsi2", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [], + "targets": [ + { + "href": "href:43", + "id": "id:44", + "name": "ni2", + "resource_type": "network_interface" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": null, + "crn": "fake:crn:5", + "href": "fake:href:5", + "id": "fake:id:5", + "name": "test-vpc1--vsi1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "direction": "outbound", + "href": "fake:href:2", + "id": "fake:id:2", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.0/31" + }, + "port_max": 10, + "port_min": 1, + "protocol": "tcp" + }, + { + "direction": "outbound", + "href": "fake:href:3", + "id": "fake:id:3", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.2/31" + }, + "port_max": 20, + "port_min": 1, + "protocol": "tcp" + }, + { + "direction": "outbound", + "href": "fake:href:4", + "id": "fake:id:4", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.4/30" + }, + "port_max": 10, + "port_min": 1, + "protocol": "tcp" + } + ], + "targets": [ + { + "href": "href:63", + "id": "id:64", + "name": "ni1", + "resource_type": "network_interface" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": null, + "crn": "fake:crn:6", + "href": "fake:href:6", + "id": "fake:id:6", + "name": "test-vpc1--vsi3b", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [], + "targets": [ + { + "href": "href:87", + "id": "id:88", + "name": "ni3b", + "resource_type": "network_interface" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": null, + "crn": "fake:crn:7", + "href": "fake:href:7", + "id": "fake:id:7", + "name": "test-vpc1--vsi3a", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [], + "targets": [ + { + "href": "href:83", + "id": "id:84", + "name": "ni3a", + "resource_type": "network_interface" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + } + ], + "endpoint_gateways": [], + "instances": [ + { + "availability_policy": { + "host_failure": "restart" + }, + "bandwidth": 4000, + "boot_volume_attachment": { + "device": { + "id": "id:149" + }, + "href": "href:147", + "id": "id:148", + "name": "falsetto-snowstorm-bankbook-agreement", + "volume": { + "crn": "crn:150", + "href": "href:151", + "id": "id:152", + "name": "prawn-trusting-pasty-dental", + "resource_type": "volume" + } + }, + "confidential_compute_mode": "disabled", + "created_at": "2024-09-09T09:11:07.000Z", + "crn": "crn:144", + "disks": [], + "enable_secure_boot": false, + "health_reasons": [], + "health_state": "ok", + "href": "href:145", + "id": "id:146", + "image": { + "crn": "crn:153", + "href": "href:154", + "id": "id:155", + "name": "server-9080", + "resource_type": "image" + }, + "lifecycle_reasons": [], + "lifecycle_state": "stable", + "memory": 4, + "metadata_service": { + "enabled": false, + "protocol": "http", + "response_hop_limit": 1 + }, + "name": "vsi2", + "network_attachments": [], + "numa_count": 1, + "primary_network_interface": { + "href": "href:43", + "id": "id:44", + "name": "ni2", + "primary_ip": { + "address": "10.240.20.4", + "href": "href:41", + "id": "id:42", + "name": "startle-percent-embellish-squeegee", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "subnet": { + "crn": "crn:24", + "href": "href:25", + "id": "id:26", + "name": "subnet2", + "resource_type": "subnet" + } + }, + "profile": { + "href": "href:156", + "name": "cx2-2x4", + "resource_type": "instance_profile" + }, + "reservation_affinity": { + "policy": "disabled", + "pool": [] + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "instance", + "startable": true, + "status": "running", + "status_reasons": [], + "total_network_bandwidth": 3000, + "total_volume_bandwidth": 1000, + "vcpu": { + "architecture": "amd64", + "count": 2, + "manufacturer": "intel" + }, + "volume_attachments": [ + { + "device": { + "id": "id:149" + }, + "href": "href:147", + "id": "id:148", + "name": "falsetto-snowstorm-bankbook-agreement", + "volume": { + "crn": "crn:150", + "href": "href:151", + "id": "id:152", + "name": "prawn-trusting-pasty-dental", + "resource_type": "volume" + } + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "network_interfaces": [ + { + "allow_ip_spoofing": false, + "created_at": "2024-09-09T09:11:07.000Z", + "floating_ips": [], + "href": "href:43", + "id": "id:44", + "name": "ni2", + "port_speed": 3000, + "primary_ip": { + "address": "10.240.20.4", + "href": "href:41", + "id": "id:42", + "name": "startle-percent-embellish-squeegee", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "security_groups": [ + { + "crn": "fake:crn:1", + "href": "fake:href:1", + "id": "fake:id:1", + "name": "test-vpc1--vsi2" + } + ], + "status": "available", + "subnet": { + "crn": "crn:24", + "href": "href:25", + "id": "id:26", + "name": "subnet2", + "resource_type": "subnet" + }, + "type": "primary" + } + ], + "tags": [] + }, + { + "availability_policy": { + "host_failure": "restart" + }, + "bandwidth": 4000, + "boot_volume_attachment": { + "device": { + "id": "id:162" + }, + "href": "href:160", + "id": "id:161", + "name": "outskirts-oversized-roundish-ludicrous", + "volume": { + "crn": "crn:163", + "href": "href:164", + "id": "id:165", + "name": "family-tackling-foothold-train", + "resource_type": "volume" + } + }, + "confidential_compute_mode": "disabled", + "created_at": "2024-09-09T09:10:52.000Z", + "crn": "crn:157", + "disks": [], + "enable_secure_boot": false, + "health_reasons": [], + "health_state": "ok", + "href": "href:158", + "id": "id:159", + "image": { + "crn": "crn:153", + "href": "href:154", + "id": "id:155", + "name": "server-9080", + "resource_type": "image" + }, + "lifecycle_reasons": [], + "lifecycle_state": "stable", + "memory": 4, + "metadata_service": { + "enabled": false, + "protocol": "http", + "response_hop_limit": 1 + }, + "name": "vsi1", + "network_attachments": [], + "numa_count": 1, + "primary_network_interface": { + "href": "href:63", + "id": "id:64", + "name": "ni1", + "primary_ip": { + "address": "10.240.10.4", + "href": "href:61", + "id": "id:62", + "name": "tableware-sprawl-shrivel-popper", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "subnet": { + "crn": "crn:47", + "href": "href:48", + "id": "id:49", + "name": "subnet1", + "resource_type": "subnet" + } + }, + "profile": { + "href": "href:156", + "name": "cx2-2x4", + "resource_type": "instance_profile" + }, + "reservation_affinity": { + "policy": "disabled", + "pool": [] + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "instance", + "startable": true, + "status": "running", + "status_reasons": [], + "total_network_bandwidth": 3000, + "total_volume_bandwidth": 1000, + "vcpu": { + "architecture": "amd64", + "count": 2, + "manufacturer": "intel" + }, + "volume_attachments": [ + { + "device": { + "id": "id:162" + }, + "href": "href:160", + "id": "id:161", + "name": "outskirts-oversized-roundish-ludicrous", + "volume": { + "crn": "crn:163", + "href": "href:164", + "id": "id:165", + "name": "family-tackling-foothold-train", + "resource_type": "volume" + } + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "network_interfaces": [ + { + "allow_ip_spoofing": false, + "created_at": "2024-09-09T09:10:52.000Z", + "floating_ips": [ + { + "address": "52.116.129.168", + "crn": "crn:94", + "href": "href:95", + "id": "id:96", + "name": "vsi1-fip" + } + ], + "href": "href:63", + "id": "id:64", + "name": "ni1", + "port_speed": 3000, + "primary_ip": { + "address": "10.240.10.4", + "href": "href:61", + "id": "id:62", + "name": "tableware-sprawl-shrivel-popper", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "security_groups": [ + { + "crn": "fake:crn:5", + "href": "fake:href:5", + "id": "fake:id:5", + "name": "test-vpc1--vsi1" + } + ], + "status": "available", + "subnet": { + "crn": "crn:47", + "href": "href:48", + "id": "id:49", + "name": "subnet1", + "resource_type": "subnet" + }, + "type": "primary" + } + ], + "tags": [] + }, + { + "availability_policy": { + "host_failure": "restart" + }, + "bandwidth": 4000, + "boot_volume_attachment": { + "device": { + "id": "id:171" + }, + "href": "href:169", + "id": "id:170", + "name": "camera-yam-headfirst-scabiosa", + "volume": { + "crn": "crn:172", + "href": "href:173", + "id": "id:174", + "name": "sprinkler-avenue-playset-dislodge", + "resource_type": "volume" + } + }, + "confidential_compute_mode": "disabled", + "created_at": "2024-09-09T09:10:35.000Z", + "crn": "crn:166", + "disks": [], + "enable_secure_boot": false, + "health_reasons": [], + "health_state": "ok", + "href": "href:167", + "id": "id:168", + "image": { + "crn": "crn:153", + "href": "href:154", + "id": "id:155", + "name": "server-9080", + "resource_type": "image" + }, + "lifecycle_reasons": [], + "lifecycle_state": "stable", + "memory": 4, + "metadata_service": { + "enabled": false, + "protocol": "http", + "response_hop_limit": 1 + }, + "name": "vsi3b", + "network_attachments": [], + "numa_count": 1, + "primary_network_interface": { + "href": "href:87", + "id": "id:88", + "name": "ni3b", + "primary_ip": { + "address": "10.240.30.5", + "href": "href:85", + "id": "id:86", + "name": "reheat-joyride-little-overprice", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "subnet": { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + } + }, + "profile": { + "href": "href:156", + "name": "cx2-2x4", + "resource_type": "instance_profile" + }, + "reservation_affinity": { + "policy": "disabled", + "pool": [] + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "instance", + "startable": true, + "status": "running", + "status_reasons": [], + "total_network_bandwidth": 3000, + "total_volume_bandwidth": 1000, + "vcpu": { + "architecture": "amd64", + "count": 2, + "manufacturer": "intel" + }, + "volume_attachments": [ + { + "device": { + "id": "id:171" + }, + "href": "href:169", + "id": "id:170", + "name": "camera-yam-headfirst-scabiosa", + "volume": { + "crn": "crn:172", + "href": "href:173", + "id": "id:174", + "name": "sprinkler-avenue-playset-dislodge", + "resource_type": "volume" + } + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "network_interfaces": [ + { + "allow_ip_spoofing": false, + "created_at": "2024-09-09T09:10:34.000Z", + "floating_ips": [], + "href": "href:87", + "id": "id:88", + "name": "ni3b", + "port_speed": 3000, + "primary_ip": { + "address": "10.240.30.5", + "href": "href:85", + "id": "id:86", + "name": "reheat-joyride-little-overprice", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "security_groups": [ + { + "crn": "fake:crn:6", + "href": "fake:href:6", + "id": "fake:id:6", + "name": "test-vpc1--vsi3b" + } + ], + "status": "available", + "subnet": { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + }, + "type": "primary" + } + ], + "tags": [] + }, + { + "availability_policy": { + "host_failure": "restart" + }, + "bandwidth": 4000, + "boot_volume_attachment": { + "device": { + "id": "id:180" + }, + "href": "href:178", + "id": "id:179", + "name": "cryptic-cork-saponify-lively", + "volume": { + "crn": "crn:181", + "href": "href:182", + "id": "id:183", + "name": "appraisal-mountains-itinerary-twine", + "resource_type": "volume" + } + }, + "confidential_compute_mode": "disabled", + "created_at": "2024-09-09T09:10:34.000Z", + "crn": "crn:175", + "disks": [], + "enable_secure_boot": false, + "health_reasons": [], + "health_state": "ok", + "href": "href:176", + "id": "id:177", + "image": { + "crn": "crn:153", + "href": "href:154", + "id": "id:155", + "name": "server-9080", + "resource_type": "image" + }, + "lifecycle_reasons": [], + "lifecycle_state": "stable", + "memory": 4, + "metadata_service": { + "enabled": false, + "protocol": "http", + "response_hop_limit": 1 + }, + "name": "vsi3a", + "network_attachments": [], + "numa_count": 1, + "primary_network_interface": { + "href": "href:83", + "id": "id:84", + "name": "ni3a", + "primary_ip": { + "address": "10.240.30.4", + "href": "href:81", + "id": "id:82", + "name": "disallow-oxidant-etching-selection", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "subnet": { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + } + }, + "profile": { + "href": "href:156", + "name": "cx2-2x4", + "resource_type": "instance_profile" + }, + "reservation_affinity": { + "policy": "disabled", + "pool": [] + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "instance", + "startable": true, + "status": "running", + "status_reasons": [], + "total_network_bandwidth": 3000, + "total_volume_bandwidth": 1000, + "vcpu": { + "architecture": "amd64", + "count": 2, + "manufacturer": "intel" + }, + "volume_attachments": [ + { + "device": { + "id": "id:180" + }, + "href": "href:178", + "id": "id:179", + "name": "cryptic-cork-saponify-lively", + "volume": { + "crn": "crn:181", + "href": "href:182", + "id": "id:183", + "name": "appraisal-mountains-itinerary-twine", + "resource_type": "volume" + } + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "network_interfaces": [ + { + "allow_ip_spoofing": false, + "created_at": "2024-09-09T09:10:34.000Z", + "floating_ips": [], + "href": "href:83", + "id": "id:84", + "name": "ni3a", + "port_speed": 3000, + "primary_ip": { + "address": "10.240.30.4", + "href": "href:81", + "id": "id:82", + "name": "disallow-oxidant-etching-selection", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "security_groups": [ + { + "crn": "fake:crn:7", + "href": "fake:href:7", + "id": "fake:id:7", + "name": "test-vpc1--vsi3a" + } + ], + "status": "available", + "subnet": { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + }, + "type": "primary" + } + ], + "tags": [] + } + ], + "virtual_nis": null, + "routing_tables": [ + { + "accept_routes_from": [ + { + "resource_type": "vpn_gateway" + }, + { + "resource_type": "vpn_server" + } + ], + "advertise_routes_to": [], + "created_at": "2024-09-09T09:09:51.000Z", + "href": "href:11", + "id": "id:12", + "is_default": true, + "lifecycle_state": "stable", + "name": "fiscally-fresh-uncanny-ceramics", + "resource_type": "routing_table", + "route_direct_link_ingress": false, + "route_internet_ingress": false, + "route_transit_gateway_ingress": false, + "route_vpc_zone_ingress": false, + "subnets": [ + { + "crn": "crn:24", + "href": "href:25", + "id": "id:26", + "name": "subnet2", + "resource_type": "subnet" + }, + { + "crn": "crn:47", + "href": "href:48", + "id": "id:49", + "name": "subnet1", + "resource_type": "subnet" + }, + { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + } + ], + "routes": [], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + } + } + ], + "load_balancers": [], + "transit_connections": null, + "transit_gateways": null, + "iks_clusters": [] +} \ No newline at end of file diff --git a/test/data/optimize_sg_t/conn_spec.json b/test/data/optimize_sg_t/conn_spec.json new file mode 100644 index 00000000..469de1d7 --- /dev/null +++ b/test/data/optimize_sg_t/conn_spec.json @@ -0,0 +1,60 @@ +{ + "externals": { + "e1": "0.0.0.0/31", + "e2": "0.0.0.2/31", + "e3": "0.0.0.4/30" + }, + "required-connections": [ + { + "src": { + "name": "vsi1", + "type": "instance" + }, + "dst": { + "name": "e1", + "type": "external" + }, + "allowed-protocols": [ + { + "protocol": "TCP", + "min_destination_port": 1, + "max_destination_port": 10 + } + ] + }, + { + "src": { + "name": "vsi1", + "type": "instance" + }, + "dst": { + "name": "e2", + "type": "external" + }, + "allowed-protocols": [ + { + "protocol": "TCP", + "min_destination_port": 1, + "max_destination_port": 20 + } + ] + }, + { + "src": { + "name": "vsi1", + "type": "instance" + }, + "dst": { + "name": "e3", + "type": "external" + }, + "allowed-protocols": [ + { + "protocol": "TCP", + "min_destination_port": 1, + "max_destination_port": 10 + } + ] + } + ] +} diff --git a/test/data/optimize_sg_t/details.txt b/test/data/optimize_sg_t/details.txt new file mode 100644 index 00000000..f0569c96 --- /dev/null +++ b/test/data/optimize_sg_t/details.txt @@ -0,0 +1,8 @@ +vsi1 --> 0.0.0.0/31 (tcp ports 1-10) +vsi1 --> 0.0.0.2/31 (tcp ports 1-20) +vsi1 --> 0.0.0.4/30 (tcp ports 1-10) + +==================================== + +vsi1 --> 0.0.0.0/29 (tcp ports 1-10) +vsi1 --> 0.0.0.2/31 (tcp ports 1-20) \ No newline at end of file diff --git a/test/data/optimize_sg_t_all/config_object.json b/test/data/optimize_sg_t_all/config_object.json new file mode 100644 index 00000000..45eaa62d --- /dev/null +++ b/test/data/optimize_sg_t_all/config_object.json @@ -0,0 +1,2007 @@ +{ + "collector_version": "0.11.0", + "provider": "ibm", + "vpcs": [ + { + "classic_access": false, + "created_at": "2024-09-09T09:09:50.000Z", + "crn": "crn:1", + "cse_source_ips": [ + { + "ip": { + "address": "10.22.217.112" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + } + }, + { + "ip": { + "address": "10.12.160.153" + }, + "zone": { + "href": "href:6", + "name": "us-south-2" + } + }, + { + "ip": { + "address": "10.16.253.223" + }, + "zone": { + "href": "href:7", + "name": "us-south-3" + } + } + ], + "default_network_acl": { + "crn": "crn:8", + "href": "href:9", + "id": "id:10", + "name": "capitol-siren-chirpy-doornail" + }, + "default_routing_table": { + "href": "href:11", + "id": "id:12", + "name": "fiscally-fresh-uncanny-ceramics", + "resource_type": "routing_table" + }, + "default_security_group": { + "crn": "crn:13", + "href": "href:14", + "id": "id:15", + "name": "wombat-hesitate-scorn-subprime" + }, + "dns": { + "enable_hub": false, + "resolution_binding_count": 0, + "resolver": { + "servers": [ + { + "address": "161.26.0.10" + }, + { + "address": "161.26.0.11" + } + ], + "type": "system", + "configuration": "default" + } + }, + "health_reasons": null, + "health_state": "ok", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "vpc", + "status": "available", + "region": "us-south", + "address_prefixes": [ + { + "cidr": "10.240.0.0/18", + "created_at": "2024-09-09T09:09:50.000Z", + "has_subnets": true, + "href": "href:18", + "id": "id:19", + "is_default": true, + "name": "filling-tasty-bacterium-parlor", + "zone": { + "href": "href:5", + "name": "us-south-1" + } + }, + { + "cidr": "10.240.64.0/18", + "created_at": "2024-09-09T09:09:50.000Z", + "has_subnets": false, + "href": "href:20", + "id": "id:21", + "is_default": true, + "name": "relearn-ragweed-goon-feisty", + "zone": { + "href": "href:6", + "name": "us-south-2" + } + }, + { + "cidr": "10.240.128.0/18", + "created_at": "2024-09-09T09:09:50.000Z", + "has_subnets": false, + "href": "href:22", + "id": "id:23", + "is_default": true, + "name": "unruffled-penknife-snowshoe-ninetieth", + "zone": { + "href": "href:7", + "name": "us-south-3" + } + } + ], + "tags": [] + } + ], + "subnets": [ + { + "available_ipv4_address_count": 250, + "created_at": "2024-09-09T09:10:51.000Z", + "crn": "crn:24", + "href": "href:25", + "id": "id:26", + "ip_version": "ipv4", + "ipv4_cidr_block": "10.240.20.0/24", + "name": "subnet2", + "network_acl": { + "crn": "crn:27", + "href": "href:28", + "id": "id:29", + "name": "acl2" + }, + "public_gateway": { + "crn": "crn:30", + "href": "href:31", + "id": "id:32", + "name": "public-gw1", + "resource_type": "public_gateway" + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "subnet", + "routing_table": { + "href": "href:11", + "id": "id:12", + "name": "fiscally-fresh-uncanny-ceramics", + "resource_type": "routing_table" + }, + "status": "available", + "total_ipv4_address_count": 256, + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "reserved_ips": [ + { + "address": "10.240.20.0", + "auto_delete": false, + "created_at": "2024-09-09T09:10:51.000Z", + "href": "href:33", + "id": "id:34", + "lifecycle_state": "stable", + "name": "ibm-network-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.20.1", + "auto_delete": false, + "created_at": "2024-09-09T09:10:51.000Z", + "href": "href:35", + "id": "id:36", + "lifecycle_state": "stable", + "name": "ibm-default-gateway", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.20.2", + "auto_delete": false, + "created_at": "2024-09-09T09:10:51.000Z", + "href": "href:37", + "id": "id:38", + "lifecycle_state": "stable", + "name": "ibm-dns-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.20.3", + "auto_delete": false, + "created_at": "2024-09-09T09:10:51.000Z", + "href": "href:39", + "id": "id:40", + "lifecycle_state": "stable", + "name": "ibm-reserved-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.20.4", + "auto_delete": true, + "created_at": "2024-09-09T09:11:08.000Z", + "href": "href:41", + "id": "id:42", + "lifecycle_state": "stable", + "name": "startle-percent-embellish-squeegee", + "owner": "user", + "resource_type": "subnet_reserved_ip", + "target": { + "href": "href:43", + "id": "id:44", + "name": "ni2", + "resource_type": "network_interface" + } + }, + { + "address": "10.240.20.255", + "auto_delete": false, + "created_at": "2024-09-09T09:10:51.000Z", + "href": "href:45", + "id": "id:46", + "lifecycle_state": "stable", + "name": "ibm-broadcast-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + } + ], + "tags": [] + }, + { + "available_ipv4_address_count": 250, + "created_at": "2024-09-09T09:10:35.000Z", + "crn": "crn:47", + "href": "href:48", + "id": "id:49", + "ip_version": "ipv4", + "ipv4_cidr_block": "10.240.10.0/24", + "name": "subnet1", + "network_acl": { + "crn": "crn:50", + "href": "href:51", + "id": "id:52", + "name": "acl1" + }, + "public_gateway": { + "crn": "crn:30", + "href": "href:31", + "id": "id:32", + "name": "public-gw1", + "resource_type": "public_gateway" + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "subnet", + "routing_table": { + "href": "href:11", + "id": "id:12", + "name": "fiscally-fresh-uncanny-ceramics", + "resource_type": "routing_table" + }, + "status": "available", + "total_ipv4_address_count": 256, + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "reserved_ips": [ + { + "address": "10.240.10.0", + "auto_delete": false, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:53", + "id": "id:54", + "lifecycle_state": "stable", + "name": "ibm-network-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.10.1", + "auto_delete": false, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:55", + "id": "id:56", + "lifecycle_state": "stable", + "name": "ibm-default-gateway", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.10.2", + "auto_delete": false, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:57", + "id": "id:58", + "lifecycle_state": "stable", + "name": "ibm-dns-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.10.3", + "auto_delete": false, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:59", + "id": "id:60", + "lifecycle_state": "stable", + "name": "ibm-reserved-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.10.4", + "auto_delete": true, + "created_at": "2024-09-09T09:10:52.000Z", + "href": "href:61", + "id": "id:62", + "lifecycle_state": "stable", + "name": "tableware-sprawl-shrivel-popper", + "owner": "user", + "resource_type": "subnet_reserved_ip", + "target": { + "href": "href:63", + "id": "id:64", + "name": "ni1", + "resource_type": "network_interface" + } + }, + { + "address": "10.240.10.255", + "auto_delete": false, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:65", + "id": "id:66", + "lifecycle_state": "stable", + "name": "ibm-broadcast-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + } + ], + "tags": [] + }, + { + "available_ipv4_address_count": 249, + "created_at": "2024-09-09T09:10:18.000Z", + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "ip_version": "ipv4", + "ipv4_cidr_block": "10.240.30.0/24", + "name": "subnet3", + "network_acl": { + "crn": "crn:70", + "href": "href:71", + "id": "id:72", + "name": "acl3" + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "subnet", + "routing_table": { + "href": "href:11", + "id": "id:12", + "name": "fiscally-fresh-uncanny-ceramics", + "resource_type": "routing_table" + }, + "status": "available", + "total_ipv4_address_count": 256, + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "reserved_ips": [ + { + "address": "10.240.30.0", + "auto_delete": false, + "created_at": "2024-09-09T09:10:18.000Z", + "href": "href:73", + "id": "id:74", + "lifecycle_state": "stable", + "name": "ibm-network-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.30.1", + "auto_delete": false, + "created_at": "2024-09-09T09:10:18.000Z", + "href": "href:75", + "id": "id:76", + "lifecycle_state": "stable", + "name": "ibm-default-gateway", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.30.2", + "auto_delete": false, + "created_at": "2024-09-09T09:10:18.000Z", + "href": "href:77", + "id": "id:78", + "lifecycle_state": "stable", + "name": "ibm-dns-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.30.3", + "auto_delete": false, + "created_at": "2024-09-09T09:10:18.000Z", + "href": "href:79", + "id": "id:80", + "lifecycle_state": "stable", + "name": "ibm-reserved-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.30.4", + "auto_delete": true, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:81", + "id": "id:82", + "lifecycle_state": "stable", + "name": "disallow-oxidant-etching-selection", + "owner": "user", + "resource_type": "subnet_reserved_ip", + "target": { + "href": "href:83", + "id": "id:84", + "name": "ni3a", + "resource_type": "network_interface" + } + }, + { + "address": "10.240.30.5", + "auto_delete": true, + "created_at": "2024-09-09T09:10:36.000Z", + "href": "href:85", + "id": "id:86", + "lifecycle_state": "stable", + "name": "reheat-joyride-little-overprice", + "owner": "user", + "resource_type": "subnet_reserved_ip", + "target": { + "href": "href:87", + "id": "id:88", + "name": "ni3b", + "resource_type": "network_interface" + } + }, + { + "address": "10.240.30.255", + "auto_delete": false, + "created_at": "2024-09-09T09:10:18.000Z", + "href": "href:89", + "id": "id:90", + "lifecycle_state": "stable", + "name": "ibm-broadcast-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + } + ], + "tags": [] + } + ], + "public_gateways": [ + { + "created_at": "2024-09-09T09:10:14.000Z", + "crn": "crn:30", + "floating_ip": { + "address": "52.118.147.142", + "crn": "crn:91", + "href": "href:92", + "id": "id:93", + "name": "public-gw1" + }, + "href": "href:31", + "id": "id:32", + "name": "public-gw1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "public_gateway", + "status": "available", + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "tags": [] + } + ], + "floating_ips": [ + { + "address": "52.116.129.168", + "created_at": "2024-09-09T09:11:31.000Z", + "crn": "crn:94", + "href": "href:95", + "id": "id:96", + "name": "vsi1-fip", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "status": "available", + "target": { + "href": "href:63", + "id": "id:64", + "name": "ni1", + "primary_ip": { + "address": "10.240.10.4", + "href": "href:61", + "id": "id:62", + "name": "tableware-sprawl-shrivel-popper", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "tags": [] + }, + { + "address": "52.118.147.142", + "created_at": "2024-09-09T09:10:14.000Z", + "crn": "crn:91", + "href": "href:92", + "id": "id:93", + "name": "public-gw1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "status": "available", + "target": { + "href": "href:31", + "id": "id:32", + "name": "public-gw1", + "resource_type": "public_gateway", + "crn": "crn:30" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "tags": [] + } + ], + "network_acls": [ + { + "created_at": "2024-09-09T09:10:15.000Z", + "crn": "crn:27", + "href": "href:28", + "id": "id:29", + "name": "acl2", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "action": "allow", + "before": { + "href": "href:99", + "id": "id:100", + "name": "acl2-out-2" + }, + "created_at": "2024-09-09T09:10:15.000Z", + "destination": "0.0.0.0/0", + "direction": "outbound", + "href": "href:97", + "id": "id:98", + "ip_version": "ipv4", + "name": "acl2-out-1", + "source": "10.240.20.0/24", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:101", + "id": "id:102", + "name": "acl2-in-1" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.10.0/24", + "direction": "outbound", + "href": "href:99", + "id": "id:100", + "ip_version": "ipv4", + "name": "acl2-out-2", + "source": "10.240.20.0/24", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:103", + "id": "id:104", + "name": "acl2-in-2" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.20.0/24", + "direction": "inbound", + "href": "href:101", + "id": "id:102", + "ip_version": "ipv4", + "name": "acl2-in-1", + "source": "0.0.0.0/0", + "protocol": "all" + }, + { + "action": "allow", + "created_at": "2024-09-09T09:10:17.000Z", + "destination": "10.240.20.0/24", + "direction": "inbound", + "href": "href:103", + "id": "id:104", + "ip_version": "ipv4", + "name": "acl2-in-2", + "source": "10.240.10.0/24", + "protocol": "all" + } + ], + "subnets": [ + { + "crn": "crn:24", + "href": "href:25", + "id": "id:26", + "name": "subnet2", + "resource_type": "subnet" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": "2024-09-09T09:10:14.000Z", + "crn": "crn:50", + "href": "href:51", + "id": "id:52", + "name": "acl1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "action": "allow", + "before": { + "href": "href:107", + "id": "id:108", + "name": "acl1-out-2" + }, + "created_at": "2024-09-09T09:10:15.000Z", + "destination": "172.217.22.46/32", + "direction": "outbound", + "href": "href:105", + "id": "id:106", + "ip_version": "ipv4", + "name": "acl1-out-1", + "source": "10.240.10.0/24", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:109", + "id": "id:110", + "name": "acl1-out-3" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.20.0/24", + "direction": "outbound", + "href": "href:107", + "id": "id:108", + "ip_version": "ipv4", + "name": "acl1-out-2", + "source": "10.240.10.0/24", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:111", + "id": "id:112", + "name": "acl1-out-4" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.30.0/24", + "direction": "outbound", + "href": "href:109", + "id": "id:110", + "ip_version": "ipv4", + "name": "acl1-out-3", + "source": "10.240.10.0/24", + "destination_port_max": 443, + "destination_port_min": 443, + "protocol": "tcp", + "source_port_max": 65535, + "source_port_min": 1 + }, + { + "action": "allow", + "before": { + "href": "href:113", + "id": "id:114", + "name": "acl1-in-1" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.30.0/24", + "direction": "outbound", + "href": "href:111", + "id": "id:112", + "ip_version": "ipv4", + "name": "acl1-out-4", + "source": "10.240.10.0/24", + "destination_port_max": 65535, + "destination_port_min": 1, + "protocol": "tcp", + "source_port_max": 443, + "source_port_min": 443 + }, + { + "action": "allow", + "before": { + "href": "href:115", + "id": "id:116", + "name": "acl1-in-2" + }, + "created_at": "2024-09-09T09:10:17.000Z", + "destination": "10.240.10.0/24", + "direction": "inbound", + "href": "href:113", + "id": "id:114", + "ip_version": "ipv4", + "name": "acl1-in-1", + "source": "172.217.22.46/32", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:117", + "id": "id:118", + "name": "acl1-in-3" + }, + "created_at": "2024-09-09T09:10:17.000Z", + "destination": "10.240.10.0/24", + "direction": "inbound", + "href": "href:115", + "id": "id:116", + "ip_version": "ipv4", + "name": "acl1-in-2", + "source": "10.240.20.0/24", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:119", + "id": "id:120", + "name": "acl1-in-4" + }, + "created_at": "2024-09-09T09:10:18.000Z", + "destination": "10.240.10.0/24", + "direction": "inbound", + "href": "href:117", + "id": "id:118", + "ip_version": "ipv4", + "name": "acl1-in-3", + "source": "10.240.30.0/24", + "destination_port_max": 65535, + "destination_port_min": 1, + "protocol": "tcp", + "source_port_max": 443, + "source_port_min": 443 + }, + { + "action": "allow", + "created_at": "2024-09-09T09:10:18.000Z", + "destination": "10.240.10.0/24", + "direction": "inbound", + "href": "href:119", + "id": "id:120", + "ip_version": "ipv4", + "name": "acl1-in-4", + "source": "10.240.30.0/24", + "destination_port_max": 443, + "destination_port_min": 443, + "protocol": "tcp", + "source_port_max": 65535, + "source_port_min": 1 + } + ], + "subnets": [ + { + "crn": "crn:47", + "href": "href:48", + "id": "id:49", + "name": "subnet1", + "resource_type": "subnet" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": "2024-09-09T09:10:14.000Z", + "crn": "crn:70", + "href": "href:71", + "id": "id:72", + "name": "acl3", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "action": "allow", + "before": { + "href": "href:123", + "id": "id:124", + "name": "acl3-out-2" + }, + "created_at": "2024-09-09T09:10:15.000Z", + "destination": "10.240.10.0/24", + "direction": "outbound", + "href": "href:121", + "id": "id:122", + "ip_version": "ipv4", + "name": "acl3-out-1", + "source": "10.240.30.0/24", + "destination_port_max": 443, + "destination_port_min": 443, + "protocol": "tcp", + "source_port_max": 65535, + "source_port_min": 1 + }, + { + "action": "allow", + "before": { + "href": "href:125", + "id": "id:126", + "name": "acl3-in-1" + }, + "created_at": "2024-09-09T09:10:15.000Z", + "destination": "10.240.10.0/24", + "direction": "outbound", + "href": "href:123", + "id": "id:124", + "ip_version": "ipv4", + "name": "acl3-out-2", + "source": "10.240.30.0/24", + "destination_port_max": 65535, + "destination_port_min": 1, + "protocol": "tcp", + "source_port_max": 443, + "source_port_min": 443 + }, + { + "action": "allow", + "before": { + "href": "href:127", + "id": "id:128", + "name": "acl3-in-2" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.30.0/24", + "direction": "inbound", + "href": "href:125", + "id": "id:126", + "ip_version": "ipv4", + "name": "acl3-in-1", + "source": "10.240.10.0/24", + "destination_port_max": 443, + "destination_port_min": 443, + "protocol": "tcp", + "source_port_max": 65535, + "source_port_min": 1 + }, + { + "action": "allow", + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.30.0/24", + "direction": "inbound", + "href": "href:127", + "id": "id:128", + "ip_version": "ipv4", + "name": "acl3-in-2", + "source": "10.240.10.0/24", + "destination_port_max": 65535, + "destination_port_min": 1, + "protocol": "tcp", + "source_port_max": 443, + "source_port_min": 443 + } + ], + "subnets": [ + { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": "2024-09-09T09:09:50.000Z", + "crn": "crn:8", + "href": "href:9", + "id": "id:10", + "name": "capitol-siren-chirpy-doornail", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "action": "allow", + "before": { + "href": "href:131", + "id": "id:132", + "name": "allow-outbound" + }, + "created_at": "2024-09-09T09:09:50.000Z", + "destination": "0.0.0.0/0", + "direction": "inbound", + "href": "href:129", + "id": "id:130", + "ip_version": "ipv4", + "name": "allow-inbound", + "source": "0.0.0.0/0", + "protocol": "all" + }, + { + "action": "allow", + "created_at": "2024-09-09T09:09:50.000Z", + "destination": "0.0.0.0/0", + "direction": "outbound", + "href": "href:131", + "id": "id:132", + "ip_version": "ipv4", + "name": "allow-outbound", + "source": "0.0.0.0/0", + "protocol": "all" + } + ], + "subnets": [], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + } + ], + "security_groups": [ + { + "created_at": "2024-09-09T09:10:14.000Z", + "crn": "crn:133", + "href": "href:134", + "id": "id:135", + "name": "sg1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "direction": "inbound", + "href": "href:136", + "id": "id:137", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.0/0" + }, + "protocol": "all" + }, + { + "direction": "outbound", + "href": "href:138", + "id": "id:139", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.0/0" + }, + "protocol": "all" + } + ], + "targets": [], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": "2024-09-09T09:09:50.000Z", + "crn": "crn:13", + "href": "href:14", + "id": "id:15", + "name": "wombat-hesitate-scorn-subprime", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "direction": "outbound", + "href": "href:140", + "id": "id:141", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.0/0" + }, + "protocol": "all" + }, + { + "direction": "inbound", + "href": "href:142", + "id": "id:143", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "crn": "crn:13", + "href": "href:14", + "id": "id:15", + "name": "wombat-hesitate-scorn-subprime" + }, + "protocol": "all" + } + ], + "targets": [], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": null, + "crn": "fake:crn:1", + "href": "fake:href:1", + "id": "fake:id:1", + "name": "test-vpc1--vsi2", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [], + "targets": [ + { + "href": "href:43", + "id": "id:44", + "name": "ni2", + "resource_type": "network_interface" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": null, + "crn": "fake:crn:5", + "href": "fake:href:5", + "id": "fake:id:5", + "name": "test-vpc1--vsi1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "direction": "outbound", + "href": "fake:href:2", + "id": "fake:id:2", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.0/31" + }, + "port_max": 10, + "port_min": 1, + "protocol": "tcp" + }, + { + "direction": "outbound", + "href": "fake:href:3", + "id": "fake:id:3", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.2/31" + }, + "protocol": "all" + }, + { + "direction": "outbound", + "href": "fake:href:4", + "id": "fake:id:4", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.4/30" + }, + "port_max": 10, + "port_min": 1, + "protocol": "tcp" + } + ], + "targets": [ + { + "href": "href:63", + "id": "id:64", + "name": "ni1", + "resource_type": "network_interface" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": null, + "crn": "fake:crn:6", + "href": "fake:href:6", + "id": "fake:id:6", + "name": "test-vpc1--vsi3b", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [], + "targets": [ + { + "href": "href:87", + "id": "id:88", + "name": "ni3b", + "resource_type": "network_interface" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": null, + "crn": "fake:crn:7", + "href": "fake:href:7", + "id": "fake:id:7", + "name": "test-vpc1--vsi3a", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [], + "targets": [ + { + "href": "href:83", + "id": "id:84", + "name": "ni3a", + "resource_type": "network_interface" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + } + ], + "endpoint_gateways": [], + "instances": [ + { + "availability_policy": { + "host_failure": "restart" + }, + "bandwidth": 4000, + "boot_volume_attachment": { + "device": { + "id": "id:149" + }, + "href": "href:147", + "id": "id:148", + "name": "falsetto-snowstorm-bankbook-agreement", + "volume": { + "crn": "crn:150", + "href": "href:151", + "id": "id:152", + "name": "prawn-trusting-pasty-dental", + "resource_type": "volume" + } + }, + "confidential_compute_mode": "disabled", + "created_at": "2024-09-09T09:11:07.000Z", + "crn": "crn:144", + "disks": [], + "enable_secure_boot": false, + "health_reasons": [], + "health_state": "ok", + "href": "href:145", + "id": "id:146", + "image": { + "crn": "crn:153", + "href": "href:154", + "id": "id:155", + "name": "server-9080", + "resource_type": "image" + }, + "lifecycle_reasons": [], + "lifecycle_state": "stable", + "memory": 4, + "metadata_service": { + "enabled": false, + "protocol": "http", + "response_hop_limit": 1 + }, + "name": "vsi2", + "network_attachments": [], + "numa_count": 1, + "primary_network_interface": { + "href": "href:43", + "id": "id:44", + "name": "ni2", + "primary_ip": { + "address": "10.240.20.4", + "href": "href:41", + "id": "id:42", + "name": "startle-percent-embellish-squeegee", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "subnet": { + "crn": "crn:24", + "href": "href:25", + "id": "id:26", + "name": "subnet2", + "resource_type": "subnet" + } + }, + "profile": { + "href": "href:156", + "name": "cx2-2x4", + "resource_type": "instance_profile" + }, + "reservation_affinity": { + "policy": "disabled", + "pool": [] + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "instance", + "startable": true, + "status": "running", + "status_reasons": [], + "total_network_bandwidth": 3000, + "total_volume_bandwidth": 1000, + "vcpu": { + "architecture": "amd64", + "count": 2, + "manufacturer": "intel" + }, + "volume_attachments": [ + { + "device": { + "id": "id:149" + }, + "href": "href:147", + "id": "id:148", + "name": "falsetto-snowstorm-bankbook-agreement", + "volume": { + "crn": "crn:150", + "href": "href:151", + "id": "id:152", + "name": "prawn-trusting-pasty-dental", + "resource_type": "volume" + } + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "network_interfaces": [ + { + "allow_ip_spoofing": false, + "created_at": "2024-09-09T09:11:07.000Z", + "floating_ips": [], + "href": "href:43", + "id": "id:44", + "name": "ni2", + "port_speed": 3000, + "primary_ip": { + "address": "10.240.20.4", + "href": "href:41", + "id": "id:42", + "name": "startle-percent-embellish-squeegee", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "security_groups": [ + { + "crn": "fake:crn:1", + "href": "fake:href:1", + "id": "fake:id:1", + "name": "test-vpc1--vsi2" + } + ], + "status": "available", + "subnet": { + "crn": "crn:24", + "href": "href:25", + "id": "id:26", + "name": "subnet2", + "resource_type": "subnet" + }, + "type": "primary" + } + ], + "tags": [] + }, + { + "availability_policy": { + "host_failure": "restart" + }, + "bandwidth": 4000, + "boot_volume_attachment": { + "device": { + "id": "id:162" + }, + "href": "href:160", + "id": "id:161", + "name": "outskirts-oversized-roundish-ludicrous", + "volume": { + "crn": "crn:163", + "href": "href:164", + "id": "id:165", + "name": "family-tackling-foothold-train", + "resource_type": "volume" + } + }, + "confidential_compute_mode": "disabled", + "created_at": "2024-09-09T09:10:52.000Z", + "crn": "crn:157", + "disks": [], + "enable_secure_boot": false, + "health_reasons": [], + "health_state": "ok", + "href": "href:158", + "id": "id:159", + "image": { + "crn": "crn:153", + "href": "href:154", + "id": "id:155", + "name": "server-9080", + "resource_type": "image" + }, + "lifecycle_reasons": [], + "lifecycle_state": "stable", + "memory": 4, + "metadata_service": { + "enabled": false, + "protocol": "http", + "response_hop_limit": 1 + }, + "name": "vsi1", + "network_attachments": [], + "numa_count": 1, + "primary_network_interface": { + "href": "href:63", + "id": "id:64", + "name": "ni1", + "primary_ip": { + "address": "10.240.10.4", + "href": "href:61", + "id": "id:62", + "name": "tableware-sprawl-shrivel-popper", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "subnet": { + "crn": "crn:47", + "href": "href:48", + "id": "id:49", + "name": "subnet1", + "resource_type": "subnet" + } + }, + "profile": { + "href": "href:156", + "name": "cx2-2x4", + "resource_type": "instance_profile" + }, + "reservation_affinity": { + "policy": "disabled", + "pool": [] + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "instance", + "startable": true, + "status": "running", + "status_reasons": [], + "total_network_bandwidth": 3000, + "total_volume_bandwidth": 1000, + "vcpu": { + "architecture": "amd64", + "count": 2, + "manufacturer": "intel" + }, + "volume_attachments": [ + { + "device": { + "id": "id:162" + }, + "href": "href:160", + "id": "id:161", + "name": "outskirts-oversized-roundish-ludicrous", + "volume": { + "crn": "crn:163", + "href": "href:164", + "id": "id:165", + "name": "family-tackling-foothold-train", + "resource_type": "volume" + } + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "network_interfaces": [ + { + "allow_ip_spoofing": false, + "created_at": "2024-09-09T09:10:52.000Z", + "floating_ips": [ + { + "address": "52.116.129.168", + "crn": "crn:94", + "href": "href:95", + "id": "id:96", + "name": "vsi1-fip" + } + ], + "href": "href:63", + "id": "id:64", + "name": "ni1", + "port_speed": 3000, + "primary_ip": { + "address": "10.240.10.4", + "href": "href:61", + "id": "id:62", + "name": "tableware-sprawl-shrivel-popper", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "security_groups": [ + { + "crn": "fake:crn:5", + "href": "fake:href:5", + "id": "fake:id:5", + "name": "test-vpc1--vsi1" + } + ], + "status": "available", + "subnet": { + "crn": "crn:47", + "href": "href:48", + "id": "id:49", + "name": "subnet1", + "resource_type": "subnet" + }, + "type": "primary" + } + ], + "tags": [] + }, + { + "availability_policy": { + "host_failure": "restart" + }, + "bandwidth": 4000, + "boot_volume_attachment": { + "device": { + "id": "id:171" + }, + "href": "href:169", + "id": "id:170", + "name": "camera-yam-headfirst-scabiosa", + "volume": { + "crn": "crn:172", + "href": "href:173", + "id": "id:174", + "name": "sprinkler-avenue-playset-dislodge", + "resource_type": "volume" + } + }, + "confidential_compute_mode": "disabled", + "created_at": "2024-09-09T09:10:35.000Z", + "crn": "crn:166", + "disks": [], + "enable_secure_boot": false, + "health_reasons": [], + "health_state": "ok", + "href": "href:167", + "id": "id:168", + "image": { + "crn": "crn:153", + "href": "href:154", + "id": "id:155", + "name": "server-9080", + "resource_type": "image" + }, + "lifecycle_reasons": [], + "lifecycle_state": "stable", + "memory": 4, + "metadata_service": { + "enabled": false, + "protocol": "http", + "response_hop_limit": 1 + }, + "name": "vsi3b", + "network_attachments": [], + "numa_count": 1, + "primary_network_interface": { + "href": "href:87", + "id": "id:88", + "name": "ni3b", + "primary_ip": { + "address": "10.240.30.5", + "href": "href:85", + "id": "id:86", + "name": "reheat-joyride-little-overprice", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "subnet": { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + } + }, + "profile": { + "href": "href:156", + "name": "cx2-2x4", + "resource_type": "instance_profile" + }, + "reservation_affinity": { + "policy": "disabled", + "pool": [] + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "instance", + "startable": true, + "status": "running", + "status_reasons": [], + "total_network_bandwidth": 3000, + "total_volume_bandwidth": 1000, + "vcpu": { + "architecture": "amd64", + "count": 2, + "manufacturer": "intel" + }, + "volume_attachments": [ + { + "device": { + "id": "id:171" + }, + "href": "href:169", + "id": "id:170", + "name": "camera-yam-headfirst-scabiosa", + "volume": { + "crn": "crn:172", + "href": "href:173", + "id": "id:174", + "name": "sprinkler-avenue-playset-dislodge", + "resource_type": "volume" + } + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "network_interfaces": [ + { + "allow_ip_spoofing": false, + "created_at": "2024-09-09T09:10:34.000Z", + "floating_ips": [], + "href": "href:87", + "id": "id:88", + "name": "ni3b", + "port_speed": 3000, + "primary_ip": { + "address": "10.240.30.5", + "href": "href:85", + "id": "id:86", + "name": "reheat-joyride-little-overprice", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "security_groups": [ + { + "crn": "fake:crn:6", + "href": "fake:href:6", + "id": "fake:id:6", + "name": "test-vpc1--vsi3b" + } + ], + "status": "available", + "subnet": { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + }, + "type": "primary" + } + ], + "tags": [] + }, + { + "availability_policy": { + "host_failure": "restart" + }, + "bandwidth": 4000, + "boot_volume_attachment": { + "device": { + "id": "id:180" + }, + "href": "href:178", + "id": "id:179", + "name": "cryptic-cork-saponify-lively", + "volume": { + "crn": "crn:181", + "href": "href:182", + "id": "id:183", + "name": "appraisal-mountains-itinerary-twine", + "resource_type": "volume" + } + }, + "confidential_compute_mode": "disabled", + "created_at": "2024-09-09T09:10:34.000Z", + "crn": "crn:175", + "disks": [], + "enable_secure_boot": false, + "health_reasons": [], + "health_state": "ok", + "href": "href:176", + "id": "id:177", + "image": { + "crn": "crn:153", + "href": "href:154", + "id": "id:155", + "name": "server-9080", + "resource_type": "image" + }, + "lifecycle_reasons": [], + "lifecycle_state": "stable", + "memory": 4, + "metadata_service": { + "enabled": false, + "protocol": "http", + "response_hop_limit": 1 + }, + "name": "vsi3a", + "network_attachments": [], + "numa_count": 1, + "primary_network_interface": { + "href": "href:83", + "id": "id:84", + "name": "ni3a", + "primary_ip": { + "address": "10.240.30.4", + "href": "href:81", + "id": "id:82", + "name": "disallow-oxidant-etching-selection", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "subnet": { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + } + }, + "profile": { + "href": "href:156", + "name": "cx2-2x4", + "resource_type": "instance_profile" + }, + "reservation_affinity": { + "policy": "disabled", + "pool": [] + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "instance", + "startable": true, + "status": "running", + "status_reasons": [], + "total_network_bandwidth": 3000, + "total_volume_bandwidth": 1000, + "vcpu": { + "architecture": "amd64", + "count": 2, + "manufacturer": "intel" + }, + "volume_attachments": [ + { + "device": { + "id": "id:180" + }, + "href": "href:178", + "id": "id:179", + "name": "cryptic-cork-saponify-lively", + "volume": { + "crn": "crn:181", + "href": "href:182", + "id": "id:183", + "name": "appraisal-mountains-itinerary-twine", + "resource_type": "volume" + } + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "network_interfaces": [ + { + "allow_ip_spoofing": false, + "created_at": "2024-09-09T09:10:34.000Z", + "floating_ips": [], + "href": "href:83", + "id": "id:84", + "name": "ni3a", + "port_speed": 3000, + "primary_ip": { + "address": "10.240.30.4", + "href": "href:81", + "id": "id:82", + "name": "disallow-oxidant-etching-selection", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "security_groups": [ + { + "crn": "fake:crn:7", + "href": "fake:href:7", + "id": "fake:id:7", + "name": "test-vpc1--vsi3a" + } + ], + "status": "available", + "subnet": { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + }, + "type": "primary" + } + ], + "tags": [] + } + ], + "virtual_nis": null, + "routing_tables": [ + { + "accept_routes_from": [ + { + "resource_type": "vpn_gateway" + }, + { + "resource_type": "vpn_server" + } + ], + "advertise_routes_to": [], + "created_at": "2024-09-09T09:09:51.000Z", + "href": "href:11", + "id": "id:12", + "is_default": true, + "lifecycle_state": "stable", + "name": "fiscally-fresh-uncanny-ceramics", + "resource_type": "routing_table", + "route_direct_link_ingress": false, + "route_internet_ingress": false, + "route_transit_gateway_ingress": false, + "route_vpc_zone_ingress": false, + "subnets": [ + { + "crn": "crn:24", + "href": "href:25", + "id": "id:26", + "name": "subnet2", + "resource_type": "subnet" + }, + { + "crn": "crn:47", + "href": "href:48", + "id": "id:49", + "name": "subnet1", + "resource_type": "subnet" + }, + { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + } + ], + "routes": [], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + } + } + ], + "load_balancers": [], + "transit_connections": null, + "transit_gateways": null, + "iks_clusters": [] +} \ No newline at end of file diff --git a/test/data/optimize_sg_t_all/conn_spec.json b/test/data/optimize_sg_t_all/conn_spec.json new file mode 100644 index 00000000..e4b6b3a9 --- /dev/null +++ b/test/data/optimize_sg_t_all/conn_spec.json @@ -0,0 +1,53 @@ +{ + "externals": { + "e1": "0.0.0.0/31", + "e2": "0.0.0.2/31", + "e3": "0.0.0.4/30" + }, + "required-connections": [ + { + "src": { + "name": "vsi1", + "type": "instance" + }, + "dst": { + "name": "e1", + "type": "external" + }, + "allowed-protocols": [ + { + "protocol": "TCP", + "min_destination_port": 1, + "max_destination_port": 10 + } + ] + }, + { + "src": { + "name": "vsi1", + "type": "instance" + }, + "dst": { + "name": "e2", + "type": "external" + } + }, + { + "src": { + "name": "vsi1", + "type": "instance" + }, + "dst": { + "name": "e3", + "type": "external" + }, + "allowed-protocols": [ + { + "protocol": "TCP", + "min_destination_port": 1, + "max_destination_port": 10 + } + ] + } + ] +} diff --git a/test/data/optimize_sg_t_all/details.txt b/test/data/optimize_sg_t_all/details.txt new file mode 100644 index 00000000..0de517d7 --- /dev/null +++ b/test/data/optimize_sg_t_all/details.txt @@ -0,0 +1,8 @@ +vsi1 --> 0.0.0.0/31 (tcp ports 1-10) +vsi1 --> 0.0.0.2/31 (all protocols) +vsi1 --> 0.0.0.4/30 (tcp ports 1-10) + +==================================== + +vsi1 --> 0.0.0.0/29 (tcp ports 1-10) +vsi1 --> 0.0.0.2/31 (all protocols) \ No newline at end of file diff --git a/test/expected/optimize_sg_protocols_to_all_csv/sg_expected.csv b/test/expected/optimize_sg_protocols_to_all_csv/sg_expected.csv new file mode 100644 index 00000000..2e4c7efb --- /dev/null +++ b/test/expected/optimize_sg_protocols_to_all_csv/sg_expected.csv @@ -0,0 +1,9 @@ +SG,Direction,Remote type,Remote,Protocol,Protocol params,Description +sg1,Inbound,CIDR block,Any IP,ALL,, +sg1,Outbound,CIDR block,Any IP,ALL,, +test-vpc1--vsi1,Outbound,Security group,test-vpc1--vsi2,ALL,, +test-vpc1--vsi1,Outbound,CIDR block,0.0.0.0/30,ICMP,"Type: Any, Code: Any", +test-vpc1--vsi1,Outbound,CIDR block,0.0.0.0/31,ALL,, +test-vpc1--vsi2,Inbound,Security group,test-vpc1--vsi1,ALL,, +wombat-hesitate-scorn-subprime,Inbound,Security group,wombat-hesitate-scorn-subprime,ALL,, +wombat-hesitate-scorn-subprime,Outbound,CIDR block,Any IP,ALL,, diff --git a/test/expected/optimize_sg_protocols_to_all_json/sg_expected.json b/test/expected/optimize_sg_protocols_to_all_json/sg_expected.json new file mode 100644 index 00000000..34f2e08d --- /dev/null +++ b/test/expected/optimize_sg_protocols_to_all_json/sg_expected.json @@ -0,0 +1,2029 @@ +{ + "collector_version": "0.11.0", + "provider": "ibm", + "vpcs": [ + { + "classic_access": false, + "created_at": "2024-09-09T09:09:50.000Z", + "crn": "crn:1", + "cse_source_ips": [ + { + "ip": { + "address": "10.22.217.112" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + } + }, + { + "ip": { + "address": "10.12.160.153" + }, + "zone": { + "href": "href:6", + "name": "us-south-2" + } + }, + { + "ip": { + "address": "10.16.253.223" + }, + "zone": { + "href": "href:7", + "name": "us-south-3" + } + } + ], + "default_network_acl": { + "crn": "crn:8", + "href": "href:9", + "id": "id:10", + "name": "capitol-siren-chirpy-doornail" + }, + "default_routing_table": { + "crn": null, + "href": "href:11", + "id": "id:12", + "name": "fiscally-fresh-uncanny-ceramics", + "resource_type": "routing_table" + }, + "default_security_group": { + "crn": "crn:13", + "href": "href:14", + "id": "id:15", + "name": "wombat-hesitate-scorn-subprime" + }, + "dns": { + "enable_hub": false, + "resolution_binding_count": 0, + "resolver": { + "servers": [ + { + "address": "161.26.0.10" + }, + { + "address": "161.26.0.11" + } + ], + "type": "system", + "configuration": "default" + } + }, + "health_reasons": null, + "health_state": "ok", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "vpc", + "status": "available", + "region": "us-south", + "address_prefixes": [ + { + "cidr": "10.240.0.0/18", + "created_at": "2024-09-09T09:09:50.000Z", + "has_subnets": true, + "href": "href:18", + "id": "id:19", + "is_default": true, + "name": "filling-tasty-bacterium-parlor", + "zone": { + "href": "href:5", + "name": "us-south-1" + } + }, + { + "cidr": "10.240.64.0/18", + "created_at": "2024-09-09T09:09:50.000Z", + "has_subnets": false, + "href": "href:20", + "id": "id:21", + "is_default": true, + "name": "relearn-ragweed-goon-feisty", + "zone": { + "href": "href:6", + "name": "us-south-2" + } + }, + { + "cidr": "10.240.128.0/18", + "created_at": "2024-09-09T09:09:50.000Z", + "has_subnets": false, + "href": "href:22", + "id": "id:23", + "is_default": true, + "name": "unruffled-penknife-snowshoe-ninetieth", + "zone": { + "href": "href:7", + "name": "us-south-3" + } + } + ], + "tags": [] + } + ], + "subnets": [ + { + "available_ipv4_address_count": 250, + "created_at": "2024-09-09T09:10:51.000Z", + "crn": "crn:24", + "href": "href:25", + "id": "id:26", + "ip_version": "ipv4", + "ipv4_cidr_block": "10.240.20.0/24", + "name": "subnet2", + "network_acl": { + "crn": "crn:27", + "href": "href:28", + "id": "id:29", + "name": "acl2" + }, + "public_gateway": { + "crn": "crn:30", + "href": "href:31", + "id": "id:32", + "name": "public-gw1", + "resource_type": "public_gateway" + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "subnet", + "routing_table": { + "crn": null, + "href": "href:11", + "id": "id:12", + "name": "fiscally-fresh-uncanny-ceramics", + "resource_type": "routing_table" + }, + "status": "available", + "total_ipv4_address_count": 256, + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "reserved_ips": [ + { + "address": "10.240.20.0", + "auto_delete": false, + "created_at": "2024-09-09T09:10:51.000Z", + "href": "href:33", + "id": "id:34", + "lifecycle_state": "stable", + "name": "ibm-network-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.20.1", + "auto_delete": false, + "created_at": "2024-09-09T09:10:51.000Z", + "href": "href:35", + "id": "id:36", + "lifecycle_state": "stable", + "name": "ibm-default-gateway", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.20.2", + "auto_delete": false, + "created_at": "2024-09-09T09:10:51.000Z", + "href": "href:37", + "id": "id:38", + "lifecycle_state": "stable", + "name": "ibm-dns-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.20.3", + "auto_delete": false, + "created_at": "2024-09-09T09:10:51.000Z", + "href": "href:39", + "id": "id:40", + "lifecycle_state": "stable", + "name": "ibm-reserved-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.20.4", + "auto_delete": true, + "created_at": "2024-09-09T09:11:08.000Z", + "href": "href:41", + "id": "id:42", + "lifecycle_state": "stable", + "name": "startle-percent-embellish-squeegee", + "owner": "user", + "resource_type": "subnet_reserved_ip", + "target": { + "href": "href:43", + "id": "id:44", + "name": "ni2", + "resource_type": "network_interface" + } + }, + { + "address": "10.240.20.255", + "auto_delete": false, + "created_at": "2024-09-09T09:10:51.000Z", + "href": "href:45", + "id": "id:46", + "lifecycle_state": "stable", + "name": "ibm-broadcast-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + } + ], + "tags": [] + }, + { + "available_ipv4_address_count": 250, + "created_at": "2024-09-09T09:10:35.000Z", + "crn": "crn:47", + "href": "href:48", + "id": "id:49", + "ip_version": "ipv4", + "ipv4_cidr_block": "10.240.10.0/24", + "name": "subnet1", + "network_acl": { + "crn": "crn:50", + "href": "href:51", + "id": "id:52", + "name": "acl1" + }, + "public_gateway": { + "crn": "crn:30", + "href": "href:31", + "id": "id:32", + "name": "public-gw1", + "resource_type": "public_gateway" + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "subnet", + "routing_table": { + "crn": null, + "href": "href:11", + "id": "id:12", + "name": "fiscally-fresh-uncanny-ceramics", + "resource_type": "routing_table" + }, + "status": "available", + "total_ipv4_address_count": 256, + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "reserved_ips": [ + { + "address": "10.240.10.0", + "auto_delete": false, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:53", + "id": "id:54", + "lifecycle_state": "stable", + "name": "ibm-network-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.10.1", + "auto_delete": false, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:55", + "id": "id:56", + "lifecycle_state": "stable", + "name": "ibm-default-gateway", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.10.2", + "auto_delete": false, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:57", + "id": "id:58", + "lifecycle_state": "stable", + "name": "ibm-dns-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.10.3", + "auto_delete": false, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:59", + "id": "id:60", + "lifecycle_state": "stable", + "name": "ibm-reserved-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.10.4", + "auto_delete": true, + "created_at": "2024-09-09T09:10:52.000Z", + "href": "href:61", + "id": "id:62", + "lifecycle_state": "stable", + "name": "tableware-sprawl-shrivel-popper", + "owner": "user", + "resource_type": "subnet_reserved_ip", + "target": { + "href": "href:63", + "id": "id:64", + "name": "ni1", + "resource_type": "network_interface" + } + }, + { + "address": "10.240.10.255", + "auto_delete": false, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:65", + "id": "id:66", + "lifecycle_state": "stable", + "name": "ibm-broadcast-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + } + ], + "tags": [] + }, + { + "available_ipv4_address_count": 249, + "created_at": "2024-09-09T09:10:18.000Z", + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "ip_version": "ipv4", + "ipv4_cidr_block": "10.240.30.0/24", + "name": "subnet3", + "network_acl": { + "crn": "crn:70", + "href": "href:71", + "id": "id:72", + "name": "acl3" + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "subnet", + "routing_table": { + "crn": null, + "href": "href:11", + "id": "id:12", + "name": "fiscally-fresh-uncanny-ceramics", + "resource_type": "routing_table" + }, + "status": "available", + "total_ipv4_address_count": 256, + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "reserved_ips": [ + { + "address": "10.240.30.0", + "auto_delete": false, + "created_at": "2024-09-09T09:10:18.000Z", + "href": "href:73", + "id": "id:74", + "lifecycle_state": "stable", + "name": "ibm-network-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.30.1", + "auto_delete": false, + "created_at": "2024-09-09T09:10:18.000Z", + "href": "href:75", + "id": "id:76", + "lifecycle_state": "stable", + "name": "ibm-default-gateway", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.30.2", + "auto_delete": false, + "created_at": "2024-09-09T09:10:18.000Z", + "href": "href:77", + "id": "id:78", + "lifecycle_state": "stable", + "name": "ibm-dns-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.30.3", + "auto_delete": false, + "created_at": "2024-09-09T09:10:18.000Z", + "href": "href:79", + "id": "id:80", + "lifecycle_state": "stable", + "name": "ibm-reserved-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.30.4", + "auto_delete": true, + "created_at": "2024-09-09T09:10:35.000Z", + "href": "href:81", + "id": "id:82", + "lifecycle_state": "stable", + "name": "disallow-oxidant-etching-selection", + "owner": "user", + "resource_type": "subnet_reserved_ip", + "target": { + "href": "href:83", + "id": "id:84", + "name": "ni3a", + "resource_type": "network_interface" + } + }, + { + "address": "10.240.30.5", + "auto_delete": true, + "created_at": "2024-09-09T09:10:36.000Z", + "href": "href:85", + "id": "id:86", + "lifecycle_state": "stable", + "name": "reheat-joyride-little-overprice", + "owner": "user", + "resource_type": "subnet_reserved_ip", + "target": { + "href": "href:87", + "id": "id:88", + "name": "ni3b", + "resource_type": "network_interface" + } + }, + { + "address": "10.240.30.255", + "auto_delete": false, + "created_at": "2024-09-09T09:10:18.000Z", + "href": "href:89", + "id": "id:90", + "lifecycle_state": "stable", + "name": "ibm-broadcast-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + } + ], + "tags": [] + } + ], + "public_gateways": [ + { + "created_at": "2024-09-09T09:10:14.000Z", + "crn": "crn:30", + "floating_ip": { + "address": "52.118.147.142", + "crn": "crn:91", + "href": "href:92", + "id": "id:93", + "name": "public-gw1" + }, + "href": "href:31", + "id": "id:32", + "name": "public-gw1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "public_gateway", + "status": "available", + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "tags": [] + } + ], + "floating_ips": [ + { + "address": "52.116.129.168", + "created_at": "2024-09-09T09:11:31.000Z", + "crn": "crn:94", + "href": "href:95", + "id": "id:96", + "name": "vsi1-fip", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "status": "available", + "target": { + "href": "href:63", + "id": "id:64", + "name": "ni1", + "primary_ip": { + "address": "10.240.10.4", + "href": "href:61", + "id": "id:62", + "name": "tableware-sprawl-shrivel-popper", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "tags": [] + }, + { + "address": "52.118.147.142", + "created_at": "2024-09-09T09:10:14.000Z", + "crn": "crn:91", + "href": "href:92", + "id": "id:93", + "name": "public-gw1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "status": "available", + "target": { + "href": "href:31", + "id": "id:32", + "name": "public-gw1", + "resource_type": "public_gateway", + "crn": "crn:30" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "tags": [] + } + ], + "network_acls": [ + { + "created_at": "2024-09-09T09:10:15.000Z", + "crn": "crn:27", + "href": "href:28", + "id": "id:29", + "name": "acl2", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "action": "allow", + "before": { + "href": "href:99", + "id": "id:100", + "name": "acl2-out-2" + }, + "created_at": "2024-09-09T09:10:15.000Z", + "destination": "0.0.0.0/0", + "direction": "outbound", + "href": "href:97", + "id": "id:98", + "ip_version": "ipv4", + "name": "acl2-out-1", + "source": "10.240.20.0/24", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:101", + "id": "id:102", + "name": "acl2-in-1" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.10.0/24", + "direction": "outbound", + "href": "href:99", + "id": "id:100", + "ip_version": "ipv4", + "name": "acl2-out-2", + "source": "10.240.20.0/24", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:103", + "id": "id:104", + "name": "acl2-in-2" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.20.0/24", + "direction": "inbound", + "href": "href:101", + "id": "id:102", + "ip_version": "ipv4", + "name": "acl2-in-1", + "source": "0.0.0.0/0", + "protocol": "all" + }, + { + "action": "allow", + "created_at": "2024-09-09T09:10:17.000Z", + "destination": "10.240.20.0/24", + "direction": "inbound", + "href": "href:103", + "id": "id:104", + "ip_version": "ipv4", + "name": "acl2-in-2", + "source": "10.240.10.0/24", + "protocol": "all" + } + ], + "subnets": [ + { + "crn": "crn:24", + "href": "href:25", + "id": "id:26", + "name": "subnet2", + "resource_type": "subnet" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": "2024-09-09T09:10:14.000Z", + "crn": "crn:50", + "href": "href:51", + "id": "id:52", + "name": "acl1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "action": "allow", + "before": { + "href": "href:107", + "id": "id:108", + "name": "acl1-out-2" + }, + "created_at": "2024-09-09T09:10:15.000Z", + "destination": "172.217.22.46/32", + "direction": "outbound", + "href": "href:105", + "id": "id:106", + "ip_version": "ipv4", + "name": "acl1-out-1", + "source": "10.240.10.0/24", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:109", + "id": "id:110", + "name": "acl1-out-3" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.20.0/24", + "direction": "outbound", + "href": "href:107", + "id": "id:108", + "ip_version": "ipv4", + "name": "acl1-out-2", + "source": "10.240.10.0/24", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:111", + "id": "id:112", + "name": "acl1-out-4" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.30.0/24", + "direction": "outbound", + "href": "href:109", + "id": "id:110", + "ip_version": "ipv4", + "name": "acl1-out-3", + "source": "10.240.10.0/24", + "destination_port_max": 443, + "destination_port_min": 443, + "protocol": "tcp", + "source_port_max": 65535, + "source_port_min": 1 + }, + { + "action": "allow", + "before": { + "href": "href:113", + "id": "id:114", + "name": "acl1-in-1" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.30.0/24", + "direction": "outbound", + "href": "href:111", + "id": "id:112", + "ip_version": "ipv4", + "name": "acl1-out-4", + "source": "10.240.10.0/24", + "destination_port_max": 65535, + "destination_port_min": 1, + "protocol": "tcp", + "source_port_max": 443, + "source_port_min": 443 + }, + { + "action": "allow", + "before": { + "href": "href:115", + "id": "id:116", + "name": "acl1-in-2" + }, + "created_at": "2024-09-09T09:10:17.000Z", + "destination": "10.240.10.0/24", + "direction": "inbound", + "href": "href:113", + "id": "id:114", + "ip_version": "ipv4", + "name": "acl1-in-1", + "source": "172.217.22.46/32", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:117", + "id": "id:118", + "name": "acl1-in-3" + }, + "created_at": "2024-09-09T09:10:17.000Z", + "destination": "10.240.10.0/24", + "direction": "inbound", + "href": "href:115", + "id": "id:116", + "ip_version": "ipv4", + "name": "acl1-in-2", + "source": "10.240.20.0/24", + "protocol": "all" + }, + { + "action": "allow", + "before": { + "href": "href:119", + "id": "id:120", + "name": "acl1-in-4" + }, + "created_at": "2024-09-09T09:10:18.000Z", + "destination": "10.240.10.0/24", + "direction": "inbound", + "href": "href:117", + "id": "id:118", + "ip_version": "ipv4", + "name": "acl1-in-3", + "source": "10.240.30.0/24", + "destination_port_max": 65535, + "destination_port_min": 1, + "protocol": "tcp", + "source_port_max": 443, + "source_port_min": 443 + }, + { + "action": "allow", + "created_at": "2024-09-09T09:10:18.000Z", + "destination": "10.240.10.0/24", + "direction": "inbound", + "href": "href:119", + "id": "id:120", + "ip_version": "ipv4", + "name": "acl1-in-4", + "source": "10.240.30.0/24", + "destination_port_max": 443, + "destination_port_min": 443, + "protocol": "tcp", + "source_port_max": 65535, + "source_port_min": 1 + } + ], + "subnets": [ + { + "crn": "crn:47", + "href": "href:48", + "id": "id:49", + "name": "subnet1", + "resource_type": "subnet" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": "2024-09-09T09:10:14.000Z", + "crn": "crn:70", + "href": "href:71", + "id": "id:72", + "name": "acl3", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "action": "allow", + "before": { + "href": "href:123", + "id": "id:124", + "name": "acl3-out-2" + }, + "created_at": "2024-09-09T09:10:15.000Z", + "destination": "10.240.10.0/24", + "direction": "outbound", + "href": "href:121", + "id": "id:122", + "ip_version": "ipv4", + "name": "acl3-out-1", + "source": "10.240.30.0/24", + "destination_port_max": 443, + "destination_port_min": 443, + "protocol": "tcp", + "source_port_max": 65535, + "source_port_min": 1 + }, + { + "action": "allow", + "before": { + "href": "href:125", + "id": "id:126", + "name": "acl3-in-1" + }, + "created_at": "2024-09-09T09:10:15.000Z", + "destination": "10.240.10.0/24", + "direction": "outbound", + "href": "href:123", + "id": "id:124", + "ip_version": "ipv4", + "name": "acl3-out-2", + "source": "10.240.30.0/24", + "destination_port_max": 65535, + "destination_port_min": 1, + "protocol": "tcp", + "source_port_max": 443, + "source_port_min": 443 + }, + { + "action": "allow", + "before": { + "href": "href:127", + "id": "id:128", + "name": "acl3-in-2" + }, + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.30.0/24", + "direction": "inbound", + "href": "href:125", + "id": "id:126", + "ip_version": "ipv4", + "name": "acl3-in-1", + "source": "10.240.10.0/24", + "destination_port_max": 443, + "destination_port_min": 443, + "protocol": "tcp", + "source_port_max": 65535, + "source_port_min": 1 + }, + { + "action": "allow", + "created_at": "2024-09-09T09:10:16.000Z", + "destination": "10.240.30.0/24", + "direction": "inbound", + "href": "href:127", + "id": "id:128", + "ip_version": "ipv4", + "name": "acl3-in-2", + "source": "10.240.10.0/24", + "destination_port_max": 65535, + "destination_port_min": 1, + "protocol": "tcp", + "source_port_max": 443, + "source_port_min": 443 + } + ], + "subnets": [ + { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": "2024-09-09T09:09:50.000Z", + "crn": "crn:8", + "href": "href:9", + "id": "id:10", + "name": "capitol-siren-chirpy-doornail", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "action": "allow", + "before": { + "href": "href:131", + "id": "id:132", + "name": "allow-outbound" + }, + "created_at": "2024-09-09T09:09:50.000Z", + "destination": "0.0.0.0/0", + "direction": "inbound", + "href": "href:129", + "id": "id:130", + "ip_version": "ipv4", + "name": "allow-inbound", + "source": "0.0.0.0/0", + "protocol": "all" + }, + { + "action": "allow", + "created_at": "2024-09-09T09:09:50.000Z", + "destination": "0.0.0.0/0", + "direction": "outbound", + "href": "href:131", + "id": "id:132", + "ip_version": "ipv4", + "name": "allow-outbound", + "source": "0.0.0.0/0", + "protocol": "all" + } + ], + "subnets": [], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + } + ], + "security_groups": [ + { + "created_at": "2024-09-09T09:10:14.000Z", + "crn": "crn:133", + "href": "href:134", + "id": "id:135", + "name": "sg1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "direction": "inbound", + "href": "href:136", + "id": "id:137", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.0/0" + }, + "protocol": "all" + }, + { + "direction": "outbound", + "href": "href:138", + "id": "id:139", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.0/0" + }, + "protocol": "all" + } + ], + "targets": [], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": "2024-09-09T09:09:50.000Z", + "crn": "crn:13", + "href": "href:14", + "id": "id:15", + "name": "wombat-hesitate-scorn-subprime", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "direction": "outbound", + "href": "href:140", + "id": "id:141", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.0/0" + }, + "protocol": "all" + }, + { + "direction": "inbound", + "href": "href:142", + "id": "id:143", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "crn": "crn:13", + "href": "href:14", + "id": "id:15", + "name": "wombat-hesitate-scorn-subprime" + }, + "protocol": "all" + } + ], + "targets": [], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": null, + "crn": "fake:crn:7", + "href": "fake:href:7", + "id": "fake:id:7", + "name": "test-vpc1--vsi2", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "direction": "inbound", + "href": "fake:href:1", + "id": "fake:id:1", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "crn": "fake:crn:2", + "href": "fake:href:2", + "id": "fake:id:2", + "name": "test-vpc1--vsi1" + }, + "protocol": "all" + } + ], + "targets": [ + { + "href": "href:43", + "id": "id:44", + "name": "ni2", + "resource_type": "network_interface" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": null, + "crn": "fake:crn:2", + "href": "fake:href:2", + "id": "fake:id:2", + "name": "test-vpc1--vsi1", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [ + { + "direction": "outbound", + "href": "fake:href:2", + "id": "fake:id:2", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "crn": "fake:crn:7", + "href": "fake:href:7", + "id": "fake:id:7", + "name": "test-vpc1--vsi2" + }, + "protocol": "all" + }, + { + "direction": "outbound", + "href": "fake:href:3", + "id": "fake:id:3", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.0/30" + }, + "protocol": "icmp" + }, + { + "direction": "outbound", + "href": "fake:href:4", + "id": "fake:id:4", + "ip_version": "ipv4", + "local": { + "cidr_block": "0.0.0.0/0" + }, + "remote": { + "cidr_block": "0.0.0.0/31" + }, + "protocol": "all" + } + ], + "targets": [ + { + "href": "href:63", + "id": "id:64", + "name": "ni1", + "resource_type": "network_interface" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": null, + "crn": "fake:crn:18", + "href": "fake:href:18", + "id": "fake:id:18", + "name": "test-vpc1--vsi3b", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [], + "targets": [ + { + "href": "href:87", + "id": "id:88", + "name": "ni3b", + "resource_type": "network_interface" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": null, + "crn": "fake:crn:19", + "href": "fake:href:19", + "id": "fake:id:19", + "name": "test-vpc1--vsi3a", + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "rules": [], + "targets": [ + { + "href": "href:83", + "id": "id:84", + "name": "ni3a", + "resource_type": "network_interface" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "tags": [] + } + ], + "endpoint_gateways": [], + "instances": [ + { + "availability_policy": { + "host_failure": "restart" + }, + "bandwidth": 4000, + "boot_volume_attachment": { + "device": { + "id": "id:149" + }, + "href": "href:147", + "id": "id:148", + "name": "falsetto-snowstorm-bankbook-agreement", + "volume": { + "crn": "crn:150", + "href": "href:151", + "id": "id:152", + "name": "prawn-trusting-pasty-dental", + "resource_type": "volume" + } + }, + "confidential_compute_mode": "disabled", + "created_at": "2024-09-09T09:11:07.000Z", + "crn": "crn:144", + "disks": [], + "enable_secure_boot": false, + "health_reasons": [], + "health_state": "ok", + "href": "href:145", + "id": "id:146", + "image": { + "crn": "crn:153", + "href": "href:154", + "id": "id:155", + "name": "server-9080", + "resource_type": "image" + }, + "lifecycle_reasons": [], + "lifecycle_state": "stable", + "memory": 4, + "metadata_service": { + "enabled": false, + "protocol": "http", + "response_hop_limit": 1 + }, + "name": "vsi2", + "network_attachments": [], + "numa_count": 1, + "primary_network_interface": { + "href": "href:43", + "id": "id:44", + "name": "ni2", + "primary_ip": { + "address": "10.240.20.4", + "href": "href:41", + "id": "id:42", + "name": "startle-percent-embellish-squeegee", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "subnet": { + "crn": "crn:24", + "href": "href:25", + "id": "id:26", + "name": "subnet2", + "resource_type": "subnet" + } + }, + "profile": { + "href": "href:156", + "name": "cx2-2x4", + "resource_type": "instance_profile" + }, + "reservation_affinity": { + "policy": "disabled", + "pool": [] + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "instance", + "startable": true, + "status": "running", + "status_reasons": [], + "total_network_bandwidth": 3000, + "total_volume_bandwidth": 1000, + "vcpu": { + "architecture": "amd64", + "count": 2, + "manufacturer": "intel" + }, + "volume_attachments": [ + { + "device": { + "id": "id:149" + }, + "href": "href:147", + "id": "id:148", + "name": "falsetto-snowstorm-bankbook-agreement", + "volume": { + "crn": "crn:150", + "href": "href:151", + "id": "id:152", + "name": "prawn-trusting-pasty-dental", + "resource_type": "volume" + } + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "network_interfaces": [ + { + "allow_ip_spoofing": false, + "created_at": "2024-09-09T09:11:07.000Z", + "floating_ips": [], + "href": "href:43", + "id": "id:44", + "name": "ni2", + "port_speed": 3000, + "primary_ip": { + "address": "10.240.20.4", + "href": "href:41", + "id": "id:42", + "name": "startle-percent-embellish-squeegee", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "security_groups": [ + { + "crn": "fake:crn:7", + "href": "fake:href:7", + "id": "fake:id:7", + "name": "test-vpc1--vsi2" + } + ], + "status": "available", + "subnet": { + "crn": "crn:24", + "href": "href:25", + "id": "id:26", + "name": "subnet2", + "resource_type": "subnet" + }, + "type": "primary" + } + ], + "tags": [] + }, + { + "availability_policy": { + "host_failure": "restart" + }, + "bandwidth": 4000, + "boot_volume_attachment": { + "device": { + "id": "id:162" + }, + "href": "href:160", + "id": "id:161", + "name": "outskirts-oversized-roundish-ludicrous", + "volume": { + "crn": "crn:163", + "href": "href:164", + "id": "id:165", + "name": "family-tackling-foothold-train", + "resource_type": "volume" + } + }, + "confidential_compute_mode": "disabled", + "created_at": "2024-09-09T09:10:52.000Z", + "crn": "crn:157", + "disks": [], + "enable_secure_boot": false, + "health_reasons": [], + "health_state": "ok", + "href": "href:158", + "id": "id:159", + "image": { + "crn": "crn:153", + "href": "href:154", + "id": "id:155", + "name": "server-9080", + "resource_type": "image" + }, + "lifecycle_reasons": [], + "lifecycle_state": "stable", + "memory": 4, + "metadata_service": { + "enabled": false, + "protocol": "http", + "response_hop_limit": 1 + }, + "name": "vsi1", + "network_attachments": [], + "numa_count": 1, + "primary_network_interface": { + "href": "href:63", + "id": "id:64", + "name": "ni1", + "primary_ip": { + "address": "10.240.10.4", + "href": "href:61", + "id": "id:62", + "name": "tableware-sprawl-shrivel-popper", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "subnet": { + "crn": "crn:47", + "href": "href:48", + "id": "id:49", + "name": "subnet1", + "resource_type": "subnet" + } + }, + "profile": { + "href": "href:156", + "name": "cx2-2x4", + "resource_type": "instance_profile" + }, + "reservation_affinity": { + "policy": "disabled", + "pool": [] + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "instance", + "startable": true, + "status": "running", + "status_reasons": [], + "total_network_bandwidth": 3000, + "total_volume_bandwidth": 1000, + "vcpu": { + "architecture": "amd64", + "count": 2, + "manufacturer": "intel" + }, + "volume_attachments": [ + { + "device": { + "id": "id:162" + }, + "href": "href:160", + "id": "id:161", + "name": "outskirts-oversized-roundish-ludicrous", + "volume": { + "crn": "crn:163", + "href": "href:164", + "id": "id:165", + "name": "family-tackling-foothold-train", + "resource_type": "volume" + } + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "network_interfaces": [ + { + "allow_ip_spoofing": false, + "created_at": "2024-09-09T09:10:52.000Z", + "floating_ips": [ + { + "address": "52.116.129.168", + "crn": "crn:94", + "href": "href:95", + "id": "id:96", + "name": "vsi1-fip" + } + ], + "href": "href:63", + "id": "id:64", + "name": "ni1", + "port_speed": 3000, + "primary_ip": { + "address": "10.240.10.4", + "href": "href:61", + "id": "id:62", + "name": "tableware-sprawl-shrivel-popper", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "security_groups": [ + { + "crn": "fake:crn:2", + "href": "fake:href:2", + "id": "fake:id:2", + "name": "test-vpc1--vsi1" + } + ], + "status": "available", + "subnet": { + "crn": "crn:47", + "href": "href:48", + "id": "id:49", + "name": "subnet1", + "resource_type": "subnet" + }, + "type": "primary" + } + ], + "tags": [] + }, + { + "availability_policy": { + "host_failure": "restart" + }, + "bandwidth": 4000, + "boot_volume_attachment": { + "device": { + "id": "id:171" + }, + "href": "href:169", + "id": "id:170", + "name": "camera-yam-headfirst-scabiosa", + "volume": { + "crn": "crn:172", + "href": "href:173", + "id": "id:174", + "name": "sprinkler-avenue-playset-dislodge", + "resource_type": "volume" + } + }, + "confidential_compute_mode": "disabled", + "created_at": "2024-09-09T09:10:35.000Z", + "crn": "crn:166", + "disks": [], + "enable_secure_boot": false, + "health_reasons": [], + "health_state": "ok", + "href": "href:167", + "id": "id:168", + "image": { + "crn": "crn:153", + "href": "href:154", + "id": "id:155", + "name": "server-9080", + "resource_type": "image" + }, + "lifecycle_reasons": [], + "lifecycle_state": "stable", + "memory": 4, + "metadata_service": { + "enabled": false, + "protocol": "http", + "response_hop_limit": 1 + }, + "name": "vsi3b", + "network_attachments": [], + "numa_count": 1, + "primary_network_interface": { + "href": "href:87", + "id": "id:88", + "name": "ni3b", + "primary_ip": { + "address": "10.240.30.5", + "href": "href:85", + "id": "id:86", + "name": "reheat-joyride-little-overprice", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "subnet": { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + } + }, + "profile": { + "href": "href:156", + "name": "cx2-2x4", + "resource_type": "instance_profile" + }, + "reservation_affinity": { + "policy": "disabled", + "pool": [] + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "instance", + "startable": true, + "status": "running", + "status_reasons": [], + "total_network_bandwidth": 3000, + "total_volume_bandwidth": 1000, + "vcpu": { + "architecture": "amd64", + "count": 2, + "manufacturer": "intel" + }, + "volume_attachments": [ + { + "device": { + "id": "id:171" + }, + "href": "href:169", + "id": "id:170", + "name": "camera-yam-headfirst-scabiosa", + "volume": { + "crn": "crn:172", + "href": "href:173", + "id": "id:174", + "name": "sprinkler-avenue-playset-dislodge", + "resource_type": "volume" + } + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "network_interfaces": [ + { + "allow_ip_spoofing": false, + "created_at": "2024-09-09T09:10:34.000Z", + "floating_ips": [], + "href": "href:87", + "id": "id:88", + "name": "ni3b", + "port_speed": 3000, + "primary_ip": { + "address": "10.240.30.5", + "href": "href:85", + "id": "id:86", + "name": "reheat-joyride-little-overprice", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "security_groups": [ + { + "crn": "fake:crn:18", + "href": "fake:href:18", + "id": "fake:id:18", + "name": "test-vpc1--vsi3b" + } + ], + "status": "available", + "subnet": { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + }, + "type": "primary" + } + ], + "tags": [] + }, + { + "availability_policy": { + "host_failure": "restart" + }, + "bandwidth": 4000, + "boot_volume_attachment": { + "device": { + "id": "id:180" + }, + "href": "href:178", + "id": "id:179", + "name": "cryptic-cork-saponify-lively", + "volume": { + "crn": "crn:181", + "href": "href:182", + "id": "id:183", + "name": "appraisal-mountains-itinerary-twine", + "resource_type": "volume" + } + }, + "confidential_compute_mode": "disabled", + "created_at": "2024-09-09T09:10:34.000Z", + "crn": "crn:175", + "disks": [], + "enable_secure_boot": false, + "health_reasons": [], + "health_state": "ok", + "href": "href:176", + "id": "id:177", + "image": { + "crn": "crn:153", + "href": "href:154", + "id": "id:155", + "name": "server-9080", + "resource_type": "image" + }, + "lifecycle_reasons": [], + "lifecycle_state": "stable", + "memory": 4, + "metadata_service": { + "enabled": false, + "protocol": "http", + "response_hop_limit": 1 + }, + "name": "vsi3a", + "network_attachments": [], + "numa_count": 1, + "primary_network_interface": { + "href": "href:83", + "id": "id:84", + "name": "ni3a", + "primary_ip": { + "address": "10.240.30.4", + "href": "href:81", + "id": "id:82", + "name": "disallow-oxidant-etching-selection", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "subnet": { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + } + }, + "profile": { + "href": "href:156", + "name": "cx2-2x4", + "resource_type": "instance_profile" + }, + "reservation_affinity": { + "policy": "disabled", + "pool": [] + }, + "resource_group": { + "href": "href:16", + "id": "id:17", + "name": "name:4" + }, + "resource_type": "instance", + "startable": true, + "status": "running", + "status_reasons": [], + "total_network_bandwidth": 3000, + "total_volume_bandwidth": 1000, + "vcpu": { + "architecture": "amd64", + "count": 2, + "manufacturer": "intel" + }, + "volume_attachments": [ + { + "device": { + "id": "id:180" + }, + "href": "href:178", + "id": "id:179", + "name": "cryptic-cork-saponify-lively", + "volume": { + "crn": "crn:181", + "href": "href:182", + "id": "id:183", + "name": "appraisal-mountains-itinerary-twine", + "resource_type": "volume" + } + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + }, + "zone": { + "href": "href:5", + "name": "us-south-1" + }, + "network_interfaces": [ + { + "allow_ip_spoofing": false, + "created_at": "2024-09-09T09:10:34.000Z", + "floating_ips": [], + "href": "href:83", + "id": "id:84", + "name": "ni3a", + "port_speed": 3000, + "primary_ip": { + "address": "10.240.30.4", + "href": "href:81", + "id": "id:82", + "name": "disallow-oxidant-etching-selection", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "security_groups": [ + { + "crn": "fake:crn:19", + "href": "fake:href:19", + "id": "fake:id:19", + "name": "test-vpc1--vsi3a" + } + ], + "status": "available", + "subnet": { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + }, + "type": "primary" + } + ], + "tags": [] + } + ], + "virtual_nis": null, + "routing_tables": [ + { + "accept_routes_from": [ + { + "resource_type": "vpn_gateway" + }, + { + "resource_type": "vpn_server" + } + ], + "advertise_routes_to": [], + "created_at": "2024-09-09T09:09:51.000Z", + "crn": null, + "href": "href:11", + "id": "id:12", + "is_default": true, + "lifecycle_state": "stable", + "name": "fiscally-fresh-uncanny-ceramics", + "resource_group": null, + "resource_type": "routing_table", + "route_direct_link_ingress": false, + "route_internet_ingress": false, + "route_transit_gateway_ingress": false, + "route_vpc_zone_ingress": false, + "subnets": [ + { + "crn": "crn:24", + "href": "href:25", + "id": "id:26", + "name": "subnet2", + "resource_type": "subnet" + }, + { + "crn": "crn:47", + "href": "href:48", + "id": "id:49", + "name": "subnet1", + "resource_type": "subnet" + }, + { + "crn": "crn:67", + "href": "href:68", + "id": "id:69", + "name": "subnet3", + "resource_type": "subnet" + } + ], + "routes": [], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1", + "resource_type": "vpc" + } + } + ], + "load_balancers": [], + "transit_connections": null, + "transit_gateways": null, + "iks_clusters": [] +} \ No newline at end of file diff --git a/test/expected/optimize_sg_protocols_to_all_md/sg_expected.md b/test/expected/optimize_sg_protocols_to_all_md/sg_expected.md new file mode 100644 index 00000000..52e2f303 --- /dev/null +++ b/test/expected/optimize_sg_protocols_to_all_md/sg_expected.md @@ -0,0 +1,10 @@ + | SG | Direction | Remote type | Remote | Protocol | Protocol params | Description | + | :--- | :--- | :--- | :--- | :--- | :--- | :--- | + | sg1 | Inbound | CIDR block | Any IP | ALL | | | + | sg1 | Outbound | CIDR block | Any IP | ALL | | | + | test-vpc1--vsi1 | Outbound | Security group | test-vpc1--vsi2 | ALL | | | + | test-vpc1--vsi1 | Outbound | CIDR block | 0.0.0.0/30 | ICMP | Type: Any, Code: Any | | + | test-vpc1--vsi1 | Outbound | CIDR block | 0.0.0.0/31 | ALL | | | + | test-vpc1--vsi2 | Inbound | Security group | test-vpc1--vsi1 | ALL | | | + | wombat-hesitate-scorn-subprime | Inbound | Security group | wombat-hesitate-scorn-subprime | ALL | | | + | wombat-hesitate-scorn-subprime | Outbound | CIDR block | Any IP | ALL | | | diff --git a/test/expected/optimize_sg_protocols_to_all_tf/sg_expected.tf b/test/expected/optimize_sg_protocols_to_all_tf/sg_expected.tf new file mode 100644 index 00000000..3b2fc12f --- /dev/null +++ b/test/expected/optimize_sg_protocols_to_all_tf/sg_expected.tf @@ -0,0 +1,83 @@ +### SG sg1 is not attached to anything +resource "ibm_is_security_group" "sg1" { + name = "sg-sg1" + resource_group = local.sg_synth_resource_group_id + vpc = local.sg_synth_test-vpc1_id +} +resource "ibm_is_security_group_rule" "sg1-0" { + group = ibm_is_security_group.sg1.id + direction = "inbound" + remote = "0.0.0.0/0" +} +resource "ibm_is_security_group_rule" "sg1-1" { + group = ibm_is_security_group.sg1.id + direction = "outbound" + remote = "0.0.0.0/0" +} + +### SG test-vpc1--vsi1 is attached to ni1 +resource "ibm_is_security_group" "test-vpc1--vsi1" { + name = "sg-test-vpc1--vsi1" + resource_group = local.sg_synth_resource_group_id + vpc = local.sg_synth_test-vpc1_id +} +resource "ibm_is_security_group_rule" "test-vpc1--vsi1-0" { + group = ibm_is_security_group.test-vpc1--vsi1.id + direction = "outbound" + remote = ibm_is_security_group.test-vpc1--vsi2.id +} +resource "ibm_is_security_group_rule" "test-vpc1--vsi1-1" { + group = ibm_is_security_group.test-vpc1--vsi1.id + direction = "outbound" + remote = "0.0.0.0/30" + icmp { + } +} +resource "ibm_is_security_group_rule" "test-vpc1--vsi1-2" { + group = ibm_is_security_group.test-vpc1--vsi1.id + direction = "outbound" + remote = "0.0.0.0/31" +} + +### SG test-vpc1--vsi2 is attached to ni2 +resource "ibm_is_security_group" "test-vpc1--vsi2" { + name = "sg-test-vpc1--vsi2" + resource_group = local.sg_synth_resource_group_id + vpc = local.sg_synth_test-vpc1_id +} +resource "ibm_is_security_group_rule" "test-vpc1--vsi2-0" { + group = ibm_is_security_group.test-vpc1--vsi2.id + direction = "inbound" + remote = ibm_is_security_group.test-vpc1--vsi1.id +} + +### SG test-vpc1--vsi3a is attached to ni3a +resource "ibm_is_security_group" "test-vpc1--vsi3a" { + name = "sg-test-vpc1--vsi3a" + resource_group = local.sg_synth_resource_group_id + vpc = local.sg_synth_test-vpc1_id +} + +### SG test-vpc1--vsi3b is attached to ni3b +resource "ibm_is_security_group" "test-vpc1--vsi3b" { + name = "sg-test-vpc1--vsi3b" + resource_group = local.sg_synth_resource_group_id + vpc = local.sg_synth_test-vpc1_id +} + +### SG wombat-hesitate-scorn-subprime is not attached to anything +resource "ibm_is_security_group" "wombat-hesitate-scorn-subprime" { + name = "sg-wombat-hesitate-scorn-subprime" + resource_group = local.sg_synth_resource_group_id + vpc = local.sg_synth_test-vpc1_id +} +resource "ibm_is_security_group_rule" "wombat-hesitate-scorn-subprime-0" { + group = ibm_is_security_group.wombat-hesitate-scorn-subprime.id + direction = "inbound" + remote = ibm_is_security_group.wombat-hesitate-scorn-subprime.id +} +resource "ibm_is_security_group_rule" "wombat-hesitate-scorn-subprime-1" { + group = ibm_is_security_group.wombat-hesitate-scorn-subprime.id + direction = "outbound" + remote = "0.0.0.0/0" +} diff --git a/test/expected/optimize_sg_redundant/sg_expected.tf b/test/expected/optimize_sg_redundant/sg_expected.tf new file mode 100644 index 00000000..5ee3d54f --- /dev/null +++ b/test/expected/optimize_sg_redundant/sg_expected.tf @@ -0,0 +1,76 @@ +### SG sg1 is not attached to anything +resource "ibm_is_security_group" "sg1" { + name = "sg-sg1" + resource_group = local.sg_synth_resource_group_id + vpc = local.sg_synth_test-vpc1_id +} +resource "ibm_is_security_group_rule" "sg1-0" { + group = ibm_is_security_group.sg1.id + direction = "inbound" + remote = "0.0.0.0/0" +} +resource "ibm_is_security_group_rule" "sg1-1" { + group = ibm_is_security_group.sg1.id + direction = "outbound" + remote = "0.0.0.0/0" +} + +### SG test-vpc1--vsi1 is attached to ni1 +resource "ibm_is_security_group" "test-vpc1--vsi1" { + name = "sg-test-vpc1--vsi1" + resource_group = local.sg_synth_resource_group_id + vpc = local.sg_synth_test-vpc1_id +} +resource "ibm_is_security_group_rule" "test-vpc1--vsi1-0" { + group = ibm_is_security_group.test-vpc1--vsi1.id + direction = "outbound" + remote = ibm_is_security_group.test-vpc1--vsi2.id +} +resource "ibm_is_security_group_rule" "test-vpc1--vsi1-1" { + group = ibm_is_security_group.test-vpc1--vsi1.id + direction = "outbound" + remote = "0.0.0.0/30" +} + +### SG test-vpc1--vsi2 is attached to ni2 +resource "ibm_is_security_group" "test-vpc1--vsi2" { + name = "sg-test-vpc1--vsi2" + resource_group = local.sg_synth_resource_group_id + vpc = local.sg_synth_test-vpc1_id +} +resource "ibm_is_security_group_rule" "test-vpc1--vsi2-0" { + group = ibm_is_security_group.test-vpc1--vsi2.id + direction = "inbound" + remote = ibm_is_security_group.test-vpc1--vsi1.id +} + +### SG test-vpc1--vsi3a is attached to ni3a +resource "ibm_is_security_group" "test-vpc1--vsi3a" { + name = "sg-test-vpc1--vsi3a" + resource_group = local.sg_synth_resource_group_id + vpc = local.sg_synth_test-vpc1_id +} + +### SG test-vpc1--vsi3b is attached to ni3b +resource "ibm_is_security_group" "test-vpc1--vsi3b" { + name = "sg-test-vpc1--vsi3b" + resource_group = local.sg_synth_resource_group_id + vpc = local.sg_synth_test-vpc1_id +} + +### SG wombat-hesitate-scorn-subprime is not attached to anything +resource "ibm_is_security_group" "wombat-hesitate-scorn-subprime" { + name = "sg-wombat-hesitate-scorn-subprime" + resource_group = local.sg_synth_resource_group_id + vpc = local.sg_synth_test-vpc1_id +} +resource "ibm_is_security_group_rule" "wombat-hesitate-scorn-subprime-0" { + group = ibm_is_security_group.wombat-hesitate-scorn-subprime.id + direction = "inbound" + remote = ibm_is_security_group.wombat-hesitate-scorn-subprime.id +} +resource "ibm_is_security_group_rule" "wombat-hesitate-scorn-subprime-1" { + group = ibm_is_security_group.wombat-hesitate-scorn-subprime.id + direction = "outbound" + remote = "0.0.0.0/0" +} diff --git a/test/expected/optimize_sg_t/sg_expected.tf b/test/expected/optimize_sg_t/sg_expected.tf new file mode 100644 index 00000000..995e1b94 --- /dev/null +++ b/test/expected/optimize_sg_t/sg_expected.tf @@ -0,0 +1,77 @@ +### SG sg1 is not attached to anything +resource "ibm_is_security_group" "sg1" { + name = "sg-sg1" + resource_group = local.sg_synth_resource_group_id + vpc = local.sg_synth_test-vpc1_id +} +resource "ibm_is_security_group_rule" "sg1-0" { + group = ibm_is_security_group.sg1.id + direction = "inbound" + remote = "0.0.0.0/0" +} +resource "ibm_is_security_group_rule" "sg1-1" { + group = ibm_is_security_group.sg1.id + direction = "outbound" + remote = "0.0.0.0/0" +} + +### SG test-vpc1--vsi1 is attached to ni1 +resource "ibm_is_security_group" "test-vpc1--vsi1" { + name = "sg-test-vpc1--vsi1" + resource_group = local.sg_synth_resource_group_id + vpc = local.sg_synth_test-vpc1_id +} +resource "ibm_is_security_group_rule" "test-vpc1--vsi1-0" { + group = ibm_is_security_group.test-vpc1--vsi1.id + direction = "outbound" + remote = "0.0.0.0/29" + tcp { + port_max = 10 + } +} +resource "ibm_is_security_group_rule" "test-vpc1--vsi1-1" { + group = ibm_is_security_group.test-vpc1--vsi1.id + direction = "outbound" + remote = "0.0.0.2/31" + tcp { + port_max = 20 + } +} + +### SG test-vpc1--vsi2 is attached to ni2 +resource "ibm_is_security_group" "test-vpc1--vsi2" { + name = "sg-test-vpc1--vsi2" + resource_group = local.sg_synth_resource_group_id + vpc = local.sg_synth_test-vpc1_id +} + +### SG test-vpc1--vsi3a is attached to ni3a +resource "ibm_is_security_group" "test-vpc1--vsi3a" { + name = "sg-test-vpc1--vsi3a" + resource_group = local.sg_synth_resource_group_id + vpc = local.sg_synth_test-vpc1_id +} + +### SG test-vpc1--vsi3b is attached to ni3b +resource "ibm_is_security_group" "test-vpc1--vsi3b" { + name = "sg-test-vpc1--vsi3b" + resource_group = local.sg_synth_resource_group_id + vpc = local.sg_synth_test-vpc1_id +} + +### SG wombat-hesitate-scorn-subprime is not attached to anything +resource "ibm_is_security_group" "wombat-hesitate-scorn-subprime" { + name = "sg-wombat-hesitate-scorn-subprime" + resource_group = local.sg_synth_resource_group_id + vpc = local.sg_synth_test-vpc1_id +} +resource "ibm_is_security_group_rule" "wombat-hesitate-scorn-subprime-0" { + group = ibm_is_security_group.wombat-hesitate-scorn-subprime.id + direction = "inbound" + remote = ibm_is_security_group.wombat-hesitate-scorn-subprime.id +} +resource "ibm_is_security_group_rule" "wombat-hesitate-scorn-subprime-1" { + group = ibm_is_security_group.wombat-hesitate-scorn-subprime.id + direction = "outbound" + remote = "0.0.0.0/0" +} diff --git a/test/expected/optimize_sg_t_all/sg_expected.tf b/test/expected/optimize_sg_t_all/sg_expected.tf new file mode 100644 index 00000000..fd5b626f --- /dev/null +++ b/test/expected/optimize_sg_t_all/sg_expected.tf @@ -0,0 +1,74 @@ +### SG sg1 is not attached to anything +resource "ibm_is_security_group" "sg1" { + name = "sg-sg1" + resource_group = local.sg_synth_resource_group_id + vpc = local.sg_synth_test-vpc1_id +} +resource "ibm_is_security_group_rule" "sg1-0" { + group = ibm_is_security_group.sg1.id + direction = "inbound" + remote = "0.0.0.0/0" +} +resource "ibm_is_security_group_rule" "sg1-1" { + group = ibm_is_security_group.sg1.id + direction = "outbound" + remote = "0.0.0.0/0" +} + +### SG test-vpc1--vsi1 is attached to ni1 +resource "ibm_is_security_group" "test-vpc1--vsi1" { + name = "sg-test-vpc1--vsi1" + resource_group = local.sg_synth_resource_group_id + vpc = local.sg_synth_test-vpc1_id +} +resource "ibm_is_security_group_rule" "test-vpc1--vsi1-0" { + group = ibm_is_security_group.test-vpc1--vsi1.id + direction = "outbound" + remote = "0.0.0.0/29" + tcp { + port_max = 10 + } +} +resource "ibm_is_security_group_rule" "test-vpc1--vsi1-1" { + group = ibm_is_security_group.test-vpc1--vsi1.id + direction = "outbound" + remote = "0.0.0.2/31" +} + +### SG test-vpc1--vsi2 is attached to ni2 +resource "ibm_is_security_group" "test-vpc1--vsi2" { + name = "sg-test-vpc1--vsi2" + resource_group = local.sg_synth_resource_group_id + vpc = local.sg_synth_test-vpc1_id +} + +### SG test-vpc1--vsi3a is attached to ni3a +resource "ibm_is_security_group" "test-vpc1--vsi3a" { + name = "sg-test-vpc1--vsi3a" + resource_group = local.sg_synth_resource_group_id + vpc = local.sg_synth_test-vpc1_id +} + +### SG test-vpc1--vsi3b is attached to ni3b +resource "ibm_is_security_group" "test-vpc1--vsi3b" { + name = "sg-test-vpc1--vsi3b" + resource_group = local.sg_synth_resource_group_id + vpc = local.sg_synth_test-vpc1_id +} + +### SG wombat-hesitate-scorn-subprime is not attached to anything +resource "ibm_is_security_group" "wombat-hesitate-scorn-subprime" { + name = "sg-wombat-hesitate-scorn-subprime" + resource_group = local.sg_synth_resource_group_id + vpc = local.sg_synth_test-vpc1_id +} +resource "ibm_is_security_group_rule" "wombat-hesitate-scorn-subprime-0" { + group = ibm_is_security_group.wombat-hesitate-scorn-subprime.id + direction = "inbound" + remote = ibm_is_security_group.wombat-hesitate-scorn-subprime.id +} +resource "ibm_is_security_group_rule" "wombat-hesitate-scorn-subprime-1" { + group = ibm_is_security_group.wombat-hesitate-scorn-subprime.id + direction = "outbound" + remote = "0.0.0.0/0" +} diff --git a/test/expected/sg_protocols_tf/sg_expected.tf b/test/expected/sg_protocols_tf/sg_expected.tf index f7519b05..a85f889c 100644 --- a/test/expected/sg_protocols_tf/sg_expected.tf +++ b/test/expected/sg_protocols_tf/sg_expected.tf @@ -1,4 +1,4 @@ -### SG attached to test-vpc0/vsi0-subnet0 +### SG test-vpc0--vsi0-subnet0 is attached to test-vpc0/vsi0-subnet0 resource "ibm_is_security_group" "test-vpc0--vsi0-subnet0" { name = "sg-test-vpc0--vsi0-subnet0" resource_group = local.sg_synth_resource_group_id @@ -21,7 +21,7 @@ resource "ibm_is_security_group_rule" "test-vpc0--vsi0-subnet0-1" { } } -### SG attached to test-vpc0/vsi0-subnet1 +### SG test-vpc0--vsi0-subnet1 is attached to test-vpc0/vsi0-subnet1 resource "ibm_is_security_group" "test-vpc0--vsi0-subnet1" { name = "sg-test-vpc0--vsi0-subnet1" resource_group = local.sg_synth_resource_group_id @@ -44,7 +44,7 @@ resource "ibm_is_security_group_rule" "test-vpc0--vsi0-subnet1-1" { } } -### SG attached to test-vpc0/vsi0-subnet2 +### SG test-vpc0--vsi0-subnet2 is attached to test-vpc0/vsi0-subnet2 resource "ibm_is_security_group" "test-vpc0--vsi0-subnet2" { name = "sg-test-vpc0--vsi0-subnet2" resource_group = local.sg_synth_resource_group_id @@ -69,7 +69,7 @@ resource "ibm_is_security_group_rule" "test-vpc0--vsi0-subnet2-1" { } } -### SG attached to test-vpc0/vsi0-subnet3 +### SG test-vpc0--vsi0-subnet3 is attached to test-vpc0/vsi0-subnet3 resource "ibm_is_security_group" "test-vpc0--vsi0-subnet3" { name = "sg-test-vpc0--vsi0-subnet3" resource_group = local.sg_synth_resource_group_id @@ -94,21 +94,21 @@ resource "ibm_is_security_group_rule" "test-vpc0--vsi0-subnet3-1" { } } -### SG attached to test-vpc0/vsi0-subnet4 +### SG test-vpc0--vsi0-subnet4 is attached to test-vpc0/vsi0-subnet4 resource "ibm_is_security_group" "test-vpc0--vsi0-subnet4" { name = "sg-test-vpc0--vsi0-subnet4" resource_group = local.sg_synth_resource_group_id vpc = local.sg_synth_test-vpc0_id } -### SG attached to test-vpc0/vsi0-subnet5 +### SG test-vpc0--vsi0-subnet5 is attached to test-vpc0/vsi0-subnet5 resource "ibm_is_security_group" "test-vpc0--vsi0-subnet5" { name = "sg-test-vpc0--vsi0-subnet5" resource_group = local.sg_synth_resource_group_id vpc = local.sg_synth_test-vpc0_id } -### SG attached to test-vpc0/vsi1-subnet0 +### SG test-vpc0--vsi1-subnet0 is attached to test-vpc0/vsi1-subnet0 resource "ibm_is_security_group" "test-vpc0--vsi1-subnet0" { name = "sg-test-vpc0--vsi1-subnet0" resource_group = local.sg_synth_resource_group_id @@ -144,7 +144,7 @@ resource "ibm_is_security_group_rule" "test-vpc0--vsi1-subnet0-2" { } } -### SG attached to test-vpc0/vsi1-subnet1 +### SG test-vpc0--vsi1-subnet1 is attached to test-vpc0/vsi1-subnet1 resource "ibm_is_security_group" "test-vpc0--vsi1-subnet1" { name = "sg-test-vpc0--vsi1-subnet1" resource_group = local.sg_synth_resource_group_id @@ -180,35 +180,35 @@ resource "ibm_is_security_group_rule" "test-vpc0--vsi1-subnet1-2" { } } -### SG attached to test-vpc0/vsi1-subnet2 +### SG test-vpc0--vsi1-subnet2 is attached to test-vpc0/vsi1-subnet2 resource "ibm_is_security_group" "test-vpc0--vsi1-subnet2" { name = "sg-test-vpc0--vsi1-subnet2" resource_group = local.sg_synth_resource_group_id vpc = local.sg_synth_test-vpc0_id } -### SG attached to test-vpc0/vsi1-subnet3 +### SG test-vpc0--vsi1-subnet3 is attached to test-vpc0/vsi1-subnet3 resource "ibm_is_security_group" "test-vpc0--vsi1-subnet3" { name = "sg-test-vpc0--vsi1-subnet3" resource_group = local.sg_synth_resource_group_id vpc = local.sg_synth_test-vpc0_id } -### SG attached to test-vpc0/vsi1-subnet4 +### SG test-vpc0--vsi1-subnet4 is attached to test-vpc0/vsi1-subnet4 resource "ibm_is_security_group" "test-vpc0--vsi1-subnet4" { name = "sg-test-vpc0--vsi1-subnet4" resource_group = local.sg_synth_resource_group_id vpc = local.sg_synth_test-vpc0_id } -### SG attached to test-vpc0/vsi1-subnet5 +### SG test-vpc0--vsi1-subnet5 is attached to test-vpc0/vsi1-subnet5 resource "ibm_is_security_group" "test-vpc0--vsi1-subnet5" { name = "sg-test-vpc0--vsi1-subnet5" resource_group = local.sg_synth_resource_group_id vpc = local.sg_synth_test-vpc0_id } -### SG attached to test-vpc1/vsi0-subnet10 +### SG test-vpc1--vsi0-subnet10 is attached to test-vpc1/vsi0-subnet10 resource "ibm_is_security_group" "test-vpc1--vsi0-subnet10" { name = "sg-test-vpc1--vsi0-subnet10" resource_group = local.sg_synth_resource_group_id @@ -223,21 +223,21 @@ resource "ibm_is_security_group_rule" "test-vpc1--vsi0-subnet10-0" { } } -### SG attached to test-vpc1/vsi0-subnet11 +### SG test-vpc1--vsi0-subnet11 is attached to test-vpc1/vsi0-subnet11 resource "ibm_is_security_group" "test-vpc1--vsi0-subnet11" { name = "sg-test-vpc1--vsi0-subnet11" resource_group = local.sg_synth_resource_group_id vpc = local.sg_synth_test-vpc1_id } -### SG attached to test-vpc2/vsi0-subnet20 +### SG test-vpc2--vsi0-subnet20 is attached to test-vpc2/vsi0-subnet20 resource "ibm_is_security_group" "test-vpc2--vsi0-subnet20" { name = "sg-test-vpc2--vsi0-subnet20" resource_group = local.sg_synth_resource_group_id vpc = local.sg_synth_test-vpc2_id } -### SG attached to test-vpc2/vsi1-subnet20 +### SG test-vpc2--vsi1-subnet20 is attached to test-vpc2/vsi1-subnet20 resource "ibm_is_security_group" "test-vpc2--vsi1-subnet20" { name = "sg-test-vpc2--vsi1-subnet20" resource_group = local.sg_synth_resource_group_id @@ -250,14 +250,14 @@ resource "ibm_is_security_group_rule" "test-vpc2--vsi1-subnet20-0" { remote = "0.0.0.0/0" } -### SG attached to test-vpc2/vsi2-subnet20 +### SG test-vpc2--vsi2-subnet20 is attached to test-vpc2/vsi2-subnet20 resource "ibm_is_security_group" "test-vpc2--vsi2-subnet20" { name = "sg-test-vpc2--vsi2-subnet20" resource_group = local.sg_synth_resource_group_id vpc = local.sg_synth_test-vpc2_id } -### SG attached to test-vpc3/vsi0-subnet30 +### SG test-vpc3--vsi0-subnet30 is attached to test-vpc3/vsi0-subnet30 resource "ibm_is_security_group" "test-vpc3--vsi0-subnet30" { name = "sg-test-vpc3--vsi0-subnet30" resource_group = local.sg_synth_resource_group_id diff --git a/test/expected/sg_testing3_tf/sg_expected.tf b/test/expected/sg_testing3_tf/sg_expected.tf index 8bfb66a3..c7ced9bf 100644 --- a/test/expected/sg_testing3_tf/sg_expected.tf +++ b/test/expected/sg_testing3_tf/sg_expected.tf @@ -1,11 +1,11 @@ -### SG attached to test-vpc/appdata-endpoint-gateway +### SG test-vpc--appdata-endpoint-gateway is attached to test-vpc/appdata-endpoint-gateway resource "ibm_is_security_group" "test-vpc--appdata-endpoint-gateway" { name = "sg-test-vpc--appdata-endpoint-gateway" resource_group = local.sg_synth_resource_group_id vpc = local.sg_synth_test-vpc_id } -### SG attached to test-vpc/be +### SG test-vpc--be is attached to test-vpc/be resource "ibm_is_security_group" "test-vpc--be" { name = "sg-test-vpc--be" resource_group = local.sg_synth_resource_group_id @@ -32,7 +32,7 @@ resource "ibm_is_security_group_rule" "test-vpc--be-2" { remote = ibm_is_security_group.test-vpc--policydb-endpoint-gateway.id } -### SG attached to test-vpc/fe +### SG test-vpc--fe is attached to test-vpc/fe resource "ibm_is_security_group" "test-vpc--fe" { name = "sg-test-vpc--fe" resource_group = local.sg_synth_resource_group_id @@ -57,7 +57,7 @@ resource "ibm_is_security_group_rule" "test-vpc--fe-1" { } } -### SG attached to test-vpc/opa +### SG test-vpc--opa is attached to test-vpc/opa resource "ibm_is_security_group" "test-vpc--opa" { name = "sg-test-vpc--opa" resource_group = local.sg_synth_resource_group_id @@ -76,7 +76,7 @@ resource "ibm_is_security_group_rule" "test-vpc--opa-1" { remote = ibm_is_security_group.test-vpc--policydb-endpoint-gateway.id } -### SG attached to test-vpc/policydb-endpoint-gateway +### SG test-vpc--policydb-endpoint-gateway is attached to test-vpc/policydb-endpoint-gateway resource "ibm_is_security_group" "test-vpc--policydb-endpoint-gateway" { name = "sg-test-vpc--policydb-endpoint-gateway" resource_group = local.sg_synth_resource_group_id @@ -95,7 +95,7 @@ resource "ibm_is_security_group_rule" "test-vpc--policydb-endpoint-gateway-1" { remote = ibm_is_security_group.test-vpc--opa.id } -### SG attached to test-vpc/proxy +### SG test-vpc--proxy is attached to test-vpc/proxy resource "ibm_is_security_group" "test-vpc--proxy" { name = "sg-test-vpc--proxy" resource_group = local.sg_synth_resource_group_id diff --git a/test/expected/sg_tg_multiple_tf_separate/test-vpc0.tf b/test/expected/sg_tg_multiple_tf_separate/test-vpc0.tf index 8f4979ba..1486e315 100644 --- a/test/expected/sg_tg_multiple_tf_separate/test-vpc0.tf +++ b/test/expected/sg_tg_multiple_tf_separate/test-vpc0.tf @@ -1,4 +1,4 @@ -### SG attached to test-vpc0/vsi0-subnet0 +### SG test-vpc0--vsi0-subnet0 is attached to test-vpc0/vsi0-subnet0 resource "ibm_is_security_group" "test-vpc0--vsi0-subnet0" { name = "sg-test-vpc0--vsi0-subnet0" resource_group = local.sg_synth_resource_group_id @@ -11,70 +11,70 @@ resource "ibm_is_security_group_rule" "test-vpc0--vsi0-subnet0-0" { remote = ibm_is_security_group.test-vpc0--vsi1-subnet4.id } -### SG attached to test-vpc0/vsi0-subnet1 +### SG test-vpc0--vsi0-subnet1 is attached to test-vpc0/vsi0-subnet1 resource "ibm_is_security_group" "test-vpc0--vsi0-subnet1" { name = "sg-test-vpc0--vsi0-subnet1" resource_group = local.sg_synth_resource_group_id vpc = local.sg_synth_test-vpc0_id } -### SG attached to test-vpc0/vsi0-subnet2 +### SG test-vpc0--vsi0-subnet2 is attached to test-vpc0/vsi0-subnet2 resource "ibm_is_security_group" "test-vpc0--vsi0-subnet2" { name = "sg-test-vpc0--vsi0-subnet2" resource_group = local.sg_synth_resource_group_id vpc = local.sg_synth_test-vpc0_id } -### SG attached to test-vpc0/vsi0-subnet3 +### SG test-vpc0--vsi0-subnet3 is attached to test-vpc0/vsi0-subnet3 resource "ibm_is_security_group" "test-vpc0--vsi0-subnet3" { name = "sg-test-vpc0--vsi0-subnet3" resource_group = local.sg_synth_resource_group_id vpc = local.sg_synth_test-vpc0_id } -### SG attached to test-vpc0/vsi0-subnet4 +### SG test-vpc0--vsi0-subnet4 is attached to test-vpc0/vsi0-subnet4 resource "ibm_is_security_group" "test-vpc0--vsi0-subnet4" { name = "sg-test-vpc0--vsi0-subnet4" resource_group = local.sg_synth_resource_group_id vpc = local.sg_synth_test-vpc0_id } -### SG attached to test-vpc0/vsi0-subnet5 +### SG test-vpc0--vsi0-subnet5 is attached to test-vpc0/vsi0-subnet5 resource "ibm_is_security_group" "test-vpc0--vsi0-subnet5" { name = "sg-test-vpc0--vsi0-subnet5" resource_group = local.sg_synth_resource_group_id vpc = local.sg_synth_test-vpc0_id } -### SG attached to test-vpc0/vsi1-subnet0 +### SG test-vpc0--vsi1-subnet0 is attached to test-vpc0/vsi1-subnet0 resource "ibm_is_security_group" "test-vpc0--vsi1-subnet0" { name = "sg-test-vpc0--vsi1-subnet0" resource_group = local.sg_synth_resource_group_id vpc = local.sg_synth_test-vpc0_id } -### SG attached to test-vpc0/vsi1-subnet1 +### SG test-vpc0--vsi1-subnet1 is attached to test-vpc0/vsi1-subnet1 resource "ibm_is_security_group" "test-vpc0--vsi1-subnet1" { name = "sg-test-vpc0--vsi1-subnet1" resource_group = local.sg_synth_resource_group_id vpc = local.sg_synth_test-vpc0_id } -### SG attached to test-vpc0/vsi1-subnet2 +### SG test-vpc0--vsi1-subnet2 is attached to test-vpc0/vsi1-subnet2 resource "ibm_is_security_group" "test-vpc0--vsi1-subnet2" { name = "sg-test-vpc0--vsi1-subnet2" resource_group = local.sg_synth_resource_group_id vpc = local.sg_synth_test-vpc0_id } -### SG attached to test-vpc0/vsi1-subnet3 +### SG test-vpc0--vsi1-subnet3 is attached to test-vpc0/vsi1-subnet3 resource "ibm_is_security_group" "test-vpc0--vsi1-subnet3" { name = "sg-test-vpc0--vsi1-subnet3" resource_group = local.sg_synth_resource_group_id vpc = local.sg_synth_test-vpc0_id } -### SG attached to test-vpc0/vsi1-subnet4 +### SG test-vpc0--vsi1-subnet4 is attached to test-vpc0/vsi1-subnet4 resource "ibm_is_security_group" "test-vpc0--vsi1-subnet4" { name = "sg-test-vpc0--vsi1-subnet4" resource_group = local.sg_synth_resource_group_id @@ -87,7 +87,7 @@ resource "ibm_is_security_group_rule" "test-vpc0--vsi1-subnet4-0" { remote = ibm_is_security_group.test-vpc0--vsi0-subnet0.id } -### SG attached to test-vpc0/vsi1-subnet5 +### SG test-vpc0--vsi1-subnet5 is attached to test-vpc0/vsi1-subnet5 resource "ibm_is_security_group" "test-vpc0--vsi1-subnet5" { name = "sg-test-vpc0--vsi1-subnet5" resource_group = local.sg_synth_resource_group_id diff --git a/test/expected/sg_tg_multiple_tf_separate/test-vpc1.tf b/test/expected/sg_tg_multiple_tf_separate/test-vpc1.tf index 06e11954..9149e693 100644 --- a/test/expected/sg_tg_multiple_tf_separate/test-vpc1.tf +++ b/test/expected/sg_tg_multiple_tf_separate/test-vpc1.tf @@ -1,4 +1,4 @@ -### SG attached to test-vpc1/vsi0-subnet10 +### SG test-vpc1--vsi0-subnet10 is attached to test-vpc1/vsi0-subnet10 resource "ibm_is_security_group" "test-vpc1--vsi0-subnet10" { name = "sg-test-vpc1--vsi0-subnet10" resource_group = local.sg_synth_resource_group_id @@ -13,7 +13,7 @@ resource "ibm_is_security_group_rule" "test-vpc1--vsi0-subnet10-0" { } } -### SG attached to test-vpc1/vsi0-subnet11 +### SG test-vpc1--vsi0-subnet11 is attached to test-vpc1/vsi0-subnet11 resource "ibm_is_security_group" "test-vpc1--vsi0-subnet11" { name = "sg-test-vpc1--vsi0-subnet11" resource_group = local.sg_synth_resource_group_id diff --git a/test/expected/sg_tg_multiple_tf_separate/test-vpc2.tf b/test/expected/sg_tg_multiple_tf_separate/test-vpc2.tf index bf96f422..7adad885 100644 --- a/test/expected/sg_tg_multiple_tf_separate/test-vpc2.tf +++ b/test/expected/sg_tg_multiple_tf_separate/test-vpc2.tf @@ -1,4 +1,4 @@ -### SG attached to test-vpc2/vsi0-subnet20 +### SG test-vpc2--vsi0-subnet20 is attached to test-vpc2/vsi0-subnet20 resource "ibm_is_security_group" "test-vpc2--vsi0-subnet20" { name = "sg-test-vpc2--vsi0-subnet20" resource_group = local.sg_synth_resource_group_id @@ -15,14 +15,14 @@ resource "ibm_is_security_group_rule" "test-vpc2--vsi0-subnet20-0" { } } -### SG attached to test-vpc2/vsi1-subnet20 +### SG test-vpc2--vsi1-subnet20 is attached to test-vpc2/vsi1-subnet20 resource "ibm_is_security_group" "test-vpc2--vsi1-subnet20" { name = "sg-test-vpc2--vsi1-subnet20" resource_group = local.sg_synth_resource_group_id vpc = local.sg_synth_test-vpc2_id } -### SG attached to test-vpc2/vsi2-subnet20 +### SG test-vpc2--vsi2-subnet20 is attached to test-vpc2/vsi2-subnet20 resource "ibm_is_security_group" "test-vpc2--vsi2-subnet20" { name = "sg-test-vpc2--vsi2-subnet20" resource_group = local.sg_synth_resource_group_id diff --git a/test/expected/sg_tg_multiple_tf_separate/test-vpc3.tf b/test/expected/sg_tg_multiple_tf_separate/test-vpc3.tf index ef77175b..312dad54 100644 --- a/test/expected/sg_tg_multiple_tf_separate/test-vpc3.tf +++ b/test/expected/sg_tg_multiple_tf_separate/test-vpc3.tf @@ -1,4 +1,4 @@ -### SG attached to test-vpc3/vsi0-subnet30 +### SG test-vpc3--vsi0-subnet30 is attached to test-vpc3/vsi0-subnet30 resource "ibm_is_security_group" "test-vpc3--vsi0-subnet30" { name = "sg-test-vpc3--vsi0-subnet30" resource_group = local.sg_synth_resource_group_id diff --git a/test/synth_test_list.go b/test/main_test_list.go similarity index 77% rename from test/synth_test_list.go rename to test/main_test_list.go index d8e37147..d6883aba 100644 --- a/test/synth_test_list.go +++ b/test/main_test_list.go @@ -24,6 +24,8 @@ const ( aclTgMultipleConfig = "%s/acl_tg_multiple/config_object.json" aclTgMultipleSpec = "%s/acl_tg_multiple/conn_spec.json" + optimizeSGProtocolsToAllConfig = "%s/optimize_sg_protocols_to_all/config_object.json" + sgProtocolsConfig = "%s/sg_protocols/config_object.json" sgProtocolsSpec = "%s/sg_protocols/conn_spec.json" @@ -34,10 +36,11 @@ const ( sgTgMultipleSpec = "%s/sg_tg_multiple/conn_spec.json" tfOutputFmt = "tf" + vsi1 = "test-vpc1--vsi1" ) func allMainTests() []testCase { - return append(synthACLTestsList(), synthSGTestsList()...) + return append(synthACLTestsList(), append(synthSGTestsList(), optimizeSGTestsLists()...)...) } //nolint:funlen //all acl synthesis tests @@ -310,3 +313,75 @@ func synthSGTestsList() []testCase { }, } } + +// Note1: spec files in data folder are used to create the config object files (acl_testing4 config) +// Note2: each data folder has a details.txt file with the test explanation +func optimizeSGTestsLists() []testCase { + return []testCase{ + { + testName: "optimize_sg_protocols_to_all_tf", + args: &command{ + cmd: optimize, + subcmd: sg, + config: optimizeSGProtocolsToAllConfig, + outputFile: "%s/optimize_sg_protocols_to_all_tf/sg_expected.tf", + }, + }, + { + testName: "optimize_sg_protocols_to_all_csv", + args: &command{ + cmd: optimize, + subcmd: sg, + config: optimizeSGProtocolsToAllConfig, + outputFile: "%s/optimize_sg_protocols_to_all_csv/sg_expected.csv", + }, + }, + { + testName: "optimize_sg_protocols_to_all_json", + args: &command{ + cmd: optimize, + subcmd: sg, + config: optimizeSGProtocolsToAllConfig, + outputFile: "%s/optimize_sg_protocols_to_all_json/sg_expected.json", + }, + }, + { + testName: "optimize_sg_protocols_to_all_md", + args: &command{ + cmd: optimize, + subcmd: sg, + config: optimizeSGProtocolsToAllConfig, + outputFile: "%s/optimize_sg_protocols_to_all_md/sg_expected.md", + }, + }, + { + testName: "optimize_sg_redundant", + args: &command{ + cmd: optimize, + subcmd: sg, + config: "%s/optimize_sg_redundant/config_object.json", + outputFile: "%s/optimize_sg_redundant/sg_expected.tf", + }, + }, + { + testName: "optimize_sg_t", + args: &command{ + cmd: optimize, + subcmd: sg, + config: "%s/optimize_sg_t/config_object.json", + outputFile: "%s/optimize_sg_t/sg_expected.tf", + firewallName: vsi1, + }, + }, + { + testName: "optimize_sg_t_all", + args: &command{ + cmd: optimize, + subcmd: sg, + config: "%s/optimize_sg_t_all/config_object.json", + outputFile: "%s/optimize_sg_t_all/sg_expected.tf", + firewallName: vsi1, + }, + }, + } +} diff --git a/test/tests_defs.go b/test/tests_defs.go index 08668069..8baea0f4 100644 --- a/test/tests_defs.go +++ b/test/tests_defs.go @@ -14,16 +14,17 @@ type testCase struct { } type command struct { - cmd string - subcmd string - singleacl bool - config string - spec string - outputFile string - outputDir string - prefix string - format string - locals bool + cmd string + subcmd string + singleacl bool + config string + spec string + outputFile string + outputDir string + prefix string + format string + locals bool + firewallName string } const ( @@ -34,9 +35,10 @@ const ( defaultDirectoryPermission = 0o755 - synth string = "synth" - acl string = "acl" - sg string = "sg" + synth string = "synth" + optimize string = "optimize" + acl string = "acl" + sg string = "sg" ) func (c *command) Args(dataFolder, resultsFolder string) []string { @@ -72,6 +74,9 @@ func (c *command) Args(dataFolder, resultsFolder string) []string { if c.locals { res = append(res, "-l") } + if c.firewallName != "" { + res = append(res, "-n", c.firewallName) + } return res }