diff --git a/pkg/drawio/abstractTreeNode.go b/pkg/drawio/abstractTreeNode.go index e60d0b0eb..b37dec67d 100644 --- a/pkg/drawio/abstractTreeNode.go +++ b/pkg/drawio/abstractTreeNode.go @@ -5,7 +5,7 @@ import "strings" const ( minID = 100 nextIDStep = 10 - niVsiID = 1 + miniIconID = 1 niFipID = 2 textID = 3 tagID = 4 diff --git a/pkg/drawio/connectivityMap.drawio.tmpl b/pkg/drawio/connectivityMap.drawio.tmpl index 018173621..851ea33bb 100644 --- a/pkg/drawio/connectivityMap.drawio.tmpl +++ b/pkg/drawio/connectivityMap.drawio.tmpl @@ -35,14 +35,12 @@ {{ end }} + {{ if $data.HasMiniIcon $node }} + + + + {{ end }} {{ if $node.IsNI }} - {{ if $node.HasVsi }} - {{ if $data.ShowNIIcon }} - - - - {{ end }} - {{ end }} {{ if $node.HasFip }} diff --git a/pkg/drawio/createMapFile.go b/pkg/drawio/createMapFile.go index 89b364647..205f742fc 100644 --- a/pkg/drawio/createMapFile.go +++ b/pkg/drawio/createMapFile.go @@ -12,17 +12,29 @@ import ( var drawioTemplate string type drawioData struct { - FipXOffset int - FipYOffset int - VSIXOffset int - VSIYOffset int - VSISize int - RootID uint - IDsPrefix string - // ShowNIIcon says if to display the NI as an NI image, or a VSI image - // the rule is that if we have a vsi icon, then we display the NI icon as an NI image - ShowNIIcon bool - Nodes []TreeNodeInterface + drawioStyles + rootID uint + Nodes []TreeNodeInterface +} + +func NewDrawioData(network SquareTreeNodeInterface) *drawioData { + allNodes := getAllNodes(network) + orderedNodes := orderNodesForDrawio(allNodes) + return &drawioData{ + newDrawioStyles(allNodes), + network.ID(), + orderedNodes, + } +} +func (data *drawioData) FipXOffset() int { return fipXOffset } +func (data *drawioData) FipYOffset() int { return fipYOffset } +func (data *drawioData) MiniIconXOffset() int { return miniIconXOffset } +func (data *drawioData) MiniIconYOffset() int { return miniIconYOffset } +func (data *drawioData) MiniIconSize() int { return miniIconSize } +func (data *drawioData) RootID() uint { return data.rootID } +func (data *drawioData) IDsPrefix() string { return idsPrefix } +func (data *drawioData) ElementComment(tn TreeNodeInterface) string { + return reflect.TypeOf(tn).Elem().Name() + " " + tn.Label() } // orderNodesForDrawio() sort the nodes for the drawio canvas @@ -54,18 +66,8 @@ func orderNodesForDrawio(nodes []TreeNodeInterface) []TreeNodeInterface { func CreateDrawioConnectivityMapFile(network SquareTreeNodeInterface, outputFile string) error { newLayout(network).layout() - allNodes := getAllNodes(network) - data := &drawioData{ - fipXOffset, - fipYOffset, - vsiXOffset, - vsiYOffset, - vsiIconSize, - network.ID(), - idsPrefix, - network.HasVSIs(), - orderNodesForDrawio(allNodes)} - return writeDrawioFile(data, outputFile) + + return writeDrawioFile(NewDrawioData(network), outputFile) } func writeDrawioFile(data *drawioData, outputFile string) error { diff --git a/pkg/drawio/drawio_test.go b/pkg/drawio/drawio_test.go index 21fad9c4b..f719fb6a9 100644 --- a/pkg/drawio/drawio_test.go +++ b/pkg/drawio/drawio_test.go @@ -12,23 +12,29 @@ func TestWithParsing(t *testing.T) { if err != nil { fmt.Println("Error when calling CreateDrawioConnectivityMapFile():", err) } - n2 := createNetwork2() - err2 := CreateDrawioConnectivityMapFile(n2, "fake2.drawio") - if err2 != nil { - fmt.Println("Error when calling CreateDrawioConnectivityMapFile():", err2) + n = createNetwork2() + err = CreateDrawioConnectivityMapFile(n, "fake2.drawio") + if err != nil { + fmt.Println("Error when calling CreateDrawioConnectivityMapFile():", err) + } + n = createNetworkGrouping() + err = CreateDrawioConnectivityMapFile(n, "grouping.drawio") + if err != nil { + fmt.Println("Error when calling CreateDrawioConnectivityMapFile():", err) } - nGrouping := createNetworkGrouping() - errGrouping := CreateDrawioConnectivityMapFile(nGrouping, "grouping.drawio") - if errGrouping != nil { - fmt.Println("Error when calling CreateDrawioConnectivityMapFile():", errGrouping) + n2 := NewNetworkTreeNode() + NewCloudTreeNode(n2, "empty Cloud") + NewPublicNetworkTreeNode(n2) + NewCloudTreeNode(n2, "empty cloud2") + err = CreateDrawioConnectivityMapFile(n2, "fake3.drawio") + if err != nil { + fmt.Println("Error when calling CreateDrawioConnectivityMapFile():", err) } - n3 := NewNetworkTreeNode() - NewCloudTreeNode(n3, "empty Cloud") - NewPublicNetworkTreeNode(n3) - NewCloudTreeNode(n3, "empty cloud2") - err3 := CreateDrawioConnectivityMapFile(n3, "fake3.drawio") - if err3 != nil { - fmt.Println("Error when calling CreateDrawioConnectivityMapFile():", err3) + + n = createNetworkAllTypes() + err = CreateDrawioConnectivityMapFile(n, "all.drawio") + if err != nil { + fmt.Println("Error when calling CreateDrawioConnectivityMapFile():", err) } } @@ -56,8 +62,10 @@ func createNetwork() SquareTreeNodeInterface { subnet111 := NewSubnetTreeNode(zone11, "subnet111", "ip", "key") - ni1 := NewNITreeNode(subnet111, sg11, "ni1") - ni2 := NewNITreeNode(subnet111, sg12, "ni2") + ni1 := NewNITreeNode(subnet111, "ni1") + ni2 := NewNITreeNode(subnet111, "ni2") + sg11.AddIcon(ni1) + sg12.AddIcon(ni2) GroupNIsWithVSI(zone11, "vsi1", []TreeNodeInterface{ni1, ni2}) @@ -65,13 +73,18 @@ func createNetwork() SquareTreeNodeInterface { gw12 := NewGatewayTreeNode(zone12, "gw12") subnet112 := NewSubnetTreeNode(zone11, "subnet112", "ip", "key") subnet121 := NewSubnetTreeNode(zone12, "subnet121", "ip", "key") - ni4 := NewNITreeNode(subnet112, sg12, "ni4") - ni4.SetVsi("svi1") - ni5 := NewNITreeNode(subnet121, sg11, "ni5") - ni5.SetVsi("svi2") + ni4 := NewNITreeNode(subnet112, "ni4") + sg12.AddIcon(ni4) + ni4.setVsi("svi1") + ni5 := NewNITreeNode(subnet121, "ni5") + sg11.AddIcon(ni5) + + ni5.setVsi("svi2") ni5.SetFIP("fip") - ni5b := NewNITreeNode(subnet121, sg11, "ni5b") - ni5b.SetVsi("svi3") + ni5b := NewNITreeNode(subnet121, "ni5b") + sg11.AddIcon(ni5b) + + ni5b.setVsi("svi3") ni5b.SetFIP("fip2") NewVpcTreeNode(cloud, "empty vpc") @@ -81,9 +94,13 @@ func createNetwork() SquareTreeNodeInterface { subnet211 := NewSubnetTreeNode(zone21, "subnet211", "ip", "key") - ni6 := NewNITreeNode(subnet211, sg21, "ni6") - ni7 := NewNITreeNode(subnet211, sg21, "ni7") - ni8 := NewNITreeNode(subnet211, sg21, "ni8") + ni6 := NewNITreeNode(subnet211, "ni6") + ni7 := NewNITreeNode(subnet211, "ni7") + ni8 := NewNITreeNode(subnet211, "ni8") + sg21.AddIcon(ni6) + sg21.AddIcon(ni7) + sg21.AddIcon(ni8) + GroupNIsWithVSI(zone21, "vsi2", []TreeNodeInterface{ni6, ni7, ni8}) zone22 := NewZoneTreeNode(vpc2, "zone22") @@ -95,26 +112,49 @@ func createNetwork() SquareTreeNodeInterface { subnet231 := NewSubnetTreeNode(zone23, "subnet231", "ip", "key") sg22 := NewSGTreeNode(vpc2, "sg22") - ni10 := NewNITreeNode(subnet221, sg22, "ni10") - ni11 := NewNITreeNode(subnet222, sg22, "ni11") - ni12 := NewNITreeNode(subnet222, sg22, "ni12") - ni13 := NewNITreeNode(subnet222, sg22, "ni13") - ni14 := NewNITreeNode(subnet222, sg22, "ni14") + ni10 := NewNITreeNode(subnet221, "ni10") + ni11 := NewNITreeNode(subnet222, "ni11") + ni12 := NewNITreeNode(subnet222, "ni12") + ni13 := NewNITreeNode(subnet222, "ni13") + ni14 := NewNITreeNode(subnet222, "ni14") + sg22.AddIcon(ni10) + sg22.AddIcon(ni11) + sg22.AddIcon(ni12) + sg22.AddIcon(ni13) + sg22.AddIcon(ni14) + + resip1 := NewResIPTreeNode(subnet211, "resip1") + resip2 := NewResIPTreeNode(subnet221, "resip2") + resip3 := NewResIPTreeNode(subnet231, "resip2") + sg22.AddIcon(resip1) + sg22.AddIcon(resip2) + sg22.AddIcon(resip3) + + NewConnectivityLineTreeNode(network, resip1, resip3, true, "c10") + GroupResIPsWithVpe(vpc2, "vpe1", []TreeNodeInterface{resip1, resip2}) + GroupResIPsWithVpe(vpc2, "vpe2", []TreeNodeInterface{resip3}) GroupNIsWithVSI(zone22, "vsi3", []TreeNodeInterface{ni10, ni13, ni14}) GroupNIsWithVSI(zone22, "vsi4", []TreeNodeInterface{ni11, ni12}) - ni20 := NewNITreeNode(subnet231, sg22, "ni20") - ni21 := NewNITreeNode(subnet231, nil, "ni21") - ni22 := NewNITreeNode(subnet231, sg22, "ni22") - ni23 := NewNITreeNode(subnet231, sg22, "ni23") - ni24 := NewNITreeNode(subnet231, nil, "ni24") - ni25 := NewNITreeNode(subnet231, sg22, "ni25") - ni26 := NewNITreeNode(subnet231, nil, "ni26") - ni27 := NewNITreeNode(subnet231, nil, "ni27") - ni28 := NewNITreeNode(subnet231, sg22, "ni28") - ni29 := NewNITreeNode(subnet231, sg22, "ni29") + ni20 := NewNITreeNode(subnet231, "ni20") + ni21 := NewNITreeNode(subnet231, "ni21") + ni22 := NewNITreeNode(subnet231, "ni22") + ni23 := NewNITreeNode(subnet231, "ni23") + ni24 := NewNITreeNode(subnet231, "ni24") + ni25 := NewNITreeNode(subnet231, "ni25") + ni26 := NewNITreeNode(subnet231, "ni26") + ni27 := NewNITreeNode(subnet231, "ni27") + ni28 := NewNITreeNode(subnet231, "ni28") + ni29 := NewNITreeNode(subnet231, "ni29") + + sg22.AddIcon(ni20) + sg22.AddIcon(ni22) + sg22.AddIcon(ni23) + sg22.AddIcon(ni25) + sg22.AddIcon(ni28) + sg22.AddIcon(ni29) gw21 := NewGatewayTreeNode(zone21, "gw21") gw22 := NewGatewayTreeNode(zone22, "gw22") @@ -164,6 +204,80 @@ func createNetwork() SquareTreeNodeInterface { return network } +func createNetworkAllTypes() SquareTreeNodeInterface { + network := NewNetworkTreeNode() + publicNetwork := NewPublicNetworkTreeNode(network) + + cloud1 := NewCloudTreeNode(network, "IBM Cloud") + vpc1 := NewVpcTreeNode(cloud1, "vpc1") + sg := NewSGTreeNode(vpc1, "sg33") + zone1 := NewZoneTreeNode(vpc1, "zone1") + subnet11 := NewSubnetTreeNode(zone1, "subnet1", "cidr1", "acl1") + subnet13 := NewSubnetTreeNode(zone1, "subnet2", "cidr2", "acl2") + + nia := NewNITreeNode(subnet11, "ni1a") + ripb := NewResIPTreeNode(subnet11, "ni1b") + nic := NewNITreeNode(subnet13, "ni1c") + nid := NewNITreeNode(subnet13, "ni1d") + nie := NewNITreeNode(subnet13, "ni1e") + sg.AddIcon(nia) + sg.AddIcon(ripb) + sg.AddIcon(nic) + sg.AddIcon(nid) + sg.AddIcon(nie) + GroupNIsWithVSI(zone1, "vsi1", []TreeNodeInterface{nia, nid}) + GroupNIsWithVSI(zone1, "vsi3", []TreeNodeInterface{nic}) + GroupNIsWithVSI(zone1, "vsi4", []TreeNodeInterface{nie}) + groupedNis11 := []IconTreeNodeInterface{nia, ripb} + groupedNis13 := []IconTreeNodeInterface{nic, nid} + nie.SetFIP("fip") + gs11 := NewGroupSquareTreeNode(subnet11, groupedNis11) + gs13 := NewGroupSquareTreeNode(subnet13, groupedNis13) + + i1 := NewInternetTreeNode(publicNetwork, "Internet2") + i2 := NewInternetTreeNode(publicNetwork, "Internet2") + u2 := NewUserTreeNode(publicNetwork, "Internet2") + + zone3 := NewZoneTreeNode(vpc1, "zone1") + subnet33 := NewSubnetTreeNode(zone3, "subnet2", "cidr2", "acl2") + ni33a := NewNITreeNode(subnet33, "ni1a") + rip33b := NewResIPTreeNode(subnet33, "ni1b") + ni33c := NewNITreeNode(subnet33, "ni1c") + rip33d := NewResIPTreeNode(subnet33, "ni1d") + ni33e := NewNITreeNode(subnet33, "ni1e") + sg.AddIcon(ni33a) + sg.AddIcon(rip33b) + sg.AddIcon(ni33c) + sg.AddIcon(rip33d) + sg.AddIcon(ni33e) + + GroupResIPsWithVpe(vpc1, "vpe1", []TreeNodeInterface{ripb, rip33d}) + GroupNIsWithVSI(zone3, "vsi2", []TreeNodeInterface{ni33a}) + GroupResIPsWithVpe(vpc1, "vpe3", []TreeNodeInterface{rip33b}) + GroupNIsWithVSI(zone3, "vsi4", []TreeNodeInterface{ni33c}) + GroupNIsWithVSI(zone3, "vsi4", []TreeNodeInterface{ni33e}) + + groupedNis33a := []IconTreeNodeInterface{ni33a, rip33b, ni33c, rip33d, ni33e} + groupedNis33b := []IconTreeNodeInterface{ni33a, rip33b} + groupedNis33c := []IconTreeNodeInterface{ni33a, rip33b, ni33c} + groupedNis33d := []IconTreeNodeInterface{ni33c, ni33e} + gs33a := NewGroupSquareTreeNode(subnet33, groupedNis33a) + gs33b := NewGroupSquareTreeNode(subnet33, groupedNis33b) + gs33c := NewGroupSquareTreeNode(subnet33, groupedNis33c) + gs33d := NewGroupSquareTreeNode(subnet33, groupedNis33d) + gw1 := NewGatewayTreeNode(zone1, "gw21") + + c1 := NewConnectivityLineTreeNode(network, nie, i1, true, "gconn1") + c1.SetRouter(nie, false) + NewConnectivityLineTreeNode(network, gs13, i2, true, "gconn1") + NewConnectivityLineTreeNode(network, gs11, gs11, true, "gconn1") + c2 := NewConnectivityLineTreeNode(network, gs33a, u2, true, "gconn1") + c2.SetRouter(gw1, false) + NewConnectivityLineTreeNode(network, gs33d, gs11, true, "gconn1") + NewConnectivityLineTreeNode(network, gs33c, gs33b, true, "gconn1") + return network +} + func createNetworkGrouping() SquareTreeNodeInterface { network := NewNetworkTreeNode() publicNetwork := NewPublicNetworkTreeNode(network) @@ -173,60 +287,71 @@ func createNetworkGrouping() SquareTreeNodeInterface { zone1 := NewZoneTreeNode(vpc1, "zone1") subnet11 := NewSubnetTreeNode(zone1, "subnet1", "cidr1", "acl1") groupedNis11 := []IconTreeNodeInterface{ - NewNITreeNode(subnet11, nil, "ni1"), - NewNITreeNode(subnet11, nil, "ni1"), + NewNITreeNode(subnet11, "ni1"), + NewNITreeNode(subnet11, "ni1"), } subnet12 := NewSubnetTreeNode(zone1, "subnet2", "cidr2", "acl2") - NewNITreeNode(subnet12, nil, "ni1") + NewNITreeNode(subnet12, "ni1") subnet13 := NewSubnetTreeNode(zone1, "subnet2", "cidr2", "acl2") groupedNis13 := []IconTreeNodeInterface{ - NewNITreeNode(subnet13, nil, "ni1"), - NewNITreeNode(subnet13, nil, "ni1"), + NewNITreeNode(subnet13, "ni1"), + NewNITreeNode(subnet13, "ni1"), } - NewNITreeNode(subnet13, nil, "ni1") + NewNITreeNode(subnet13, "ni1") zone2 := NewZoneTreeNode(vpc1, "zone1") subnet21 := NewSubnetTreeNode(zone2, "subnet1", "cidr1", "acl1") - NewNITreeNode(subnet21, nil, "ni1") - NewNITreeNode(subnet21, nil, "ni1") - NewNITreeNode(subnet21, nil, "ni1") + NewNITreeNode(subnet21, "ni1") + NewNITreeNode(subnet21, "ni1") + NewNITreeNode(subnet21, "ni1") subnet22 := NewSubnetTreeNode(zone2, "subnet2", "cidr2", "acl2") - NewNITreeNode(subnet22, nil, "ni1") + NewNITreeNode(subnet22, "ni1") subnet23 := NewSubnetTreeNode(zone2, "subnet2", "cidr2", "acl2") groupedNis23 := []IconTreeNodeInterface{ - NewNITreeNode(subnet23, nil, "ni1"), - NewNITreeNode(subnet23, nil, "ni1"), - NewNITreeNode(subnet23, nil, "ni1"), + NewNITreeNode(subnet23, "ni1"), + NewNITreeNode(subnet23, "ni1"), + NewNITreeNode(subnet23, "ni1"), } zone3 := NewZoneTreeNode(vpc1, "zone1") subnet31 := NewSubnetTreeNode(zone3, "subnet1", "cidr1", "acl1") groupedNis31 := []IconTreeNodeInterface{ - NewNITreeNode(subnet31, nil, "ni1"), - NewNITreeNode(subnet31, nil, "ni1"), + NewNITreeNode(subnet31, "ni1"), + NewNITreeNode(subnet31, "ni1"), } - NewNITreeNode(subnet31, nil, "ni1") + NewNITreeNode(subnet31, "ni1") subnet32 := NewSubnetTreeNode(zone3, "subnet2", "cidr2", "acl2") groupedNis32 := []IconTreeNodeInterface{ - NewNITreeNode(subnet32, nil, "ni1"), - NewNITreeNode(subnet32, nil, "ni1"), - NewNITreeNode(subnet32, nil, "ni1"), - NewNITreeNode(subnet32, nil, "ni1"), - NewNITreeNode(subnet32, nil, "ni1"), + NewNITreeNode(subnet32, "ni1"), + NewNITreeNode(subnet32, "ni1"), + NewNITreeNode(subnet32, "ni1"), + NewNITreeNode(subnet32, "ni1"), + NewNITreeNode(subnet32, "ni1"), } subnet33 := NewSubnetTreeNode(zone3, "subnet2", "cidr2", "acl2") sg33 := NewSGTreeNode(vpc1, "sg33") - ni33b := NewNITreeNode(subnet33, sg33, "ni1b") - ni33c := NewNITreeNode(subnet33, sg33, "ni1c") - ni33g := NewNITreeNode(subnet33, sg33, "ni1g") - ni33h := NewNITreeNode(subnet33, sg33, "ni1h") - ni33d := NewNITreeNode(subnet33, sg33, "ni1d") - ni33j := NewNITreeNode(subnet33, sg33, "ni1j") - ni33e := NewNITreeNode(subnet33, sg33, "ni1e") - ni33a := NewNITreeNode(subnet33, sg33, "ni1a") - ni33f := NewNITreeNode(subnet33, sg33, "ni1f") - ni33i := NewNITreeNode(subnet33, sg33, "ni1i") + ni33b := NewNITreeNode(subnet33, "ni1b") + ni33c := NewNITreeNode(subnet33, "ni1c") + ni33g := NewNITreeNode(subnet33, "ni1g") + ni33h := NewNITreeNode(subnet33, "ni1h") + ni33d := NewNITreeNode(subnet33, "ni1d") + ni33j := NewNITreeNode(subnet33, "ni1j") + ni33e := NewNITreeNode(subnet33, "ni1e") + ni33a := NewNITreeNode(subnet33, "ni1a") + ni33f := NewNITreeNode(subnet33, "ni1f") + ni33i := NewNITreeNode(subnet33, "ni1i") + sg33.AddIcon(ni33b) + sg33.AddIcon(ni33c) + sg33.AddIcon(ni33g) + sg33.AddIcon(ni33h) + sg33.AddIcon(ni33d) + sg33.AddIcon(ni33j) + sg33.AddIcon(ni33e) + sg33.AddIcon(ni33a) + sg33.AddIcon(ni33f) + sg33.AddIcon(ni33i) + groupedNis33f := []IconTreeNodeInterface{ni33h, ni33i} groupedNis33b := []IconTreeNodeInterface{ni33a, ni33b} groupedNis33a := []IconTreeNodeInterface{ni33a, ni33b, ni33c, ni33d, ni33e} @@ -284,7 +409,7 @@ func createNetwork2() SquareTreeNodeInterface { zone2 := NewZoneTreeNode(vpc2, "zone1") subnet2 := NewSubnetTreeNode(zone2, "subnet2", "cidr1", "acl1") NewVpcTreeNode(cloud2, "vpc3") - ni20 := NewNITreeNode(subnet2, nil, "ni20") + ni20 := NewNITreeNode(subnet2, "ni20") ni20.SetTooltip([]string{"this is ni20 tool tip", "with lines"}) NewConnectivityLineTreeNode(network, ni20, i4, false, "conn20") @@ -295,22 +420,28 @@ func createNetwork2() SquareTreeNodeInterface { subnet1 := NewSubnetTreeNode(zone1, "subnet1", "cidr1", "acl1") sg1 := NewSGTreeNode(vpc1, "sg1") - ni1 := NewNITreeNode(subnet1, sg1, "ni1") - ni1b := NewNITreeNode(subnet1, sg1, "ni1") + ni1 := NewNITreeNode(subnet1, "ni1") + ni1b := NewNITreeNode(subnet1, "ni1") + sg1.AddIcon(ni1) + sg1.AddIcon(ni1b) + ni1.SetTooltip([]string{"this is ni1 tool tip one line"}) GroupNIsWithVSI(zone1, "vsi1", []TreeNodeInterface{ni1, ni1b}) sg2 := NewSGTreeNode(vpc1, "sg2") - ni2 := NewNITreeNode(subnet1, sg2, "ni2") + ni2 := NewNITreeNode(subnet1, "ni2") + sg2.AddIcon(ni2) GroupNIsWithVSI(zone1, "vsi2", []TreeNodeInterface{ni2}) ni2.SetFIP("fip") sg3 := NewSGTreeNode(vpc1, "sg3") - ni3 := NewNITreeNode(subnet1, sg3, "ni3") + ni3 := NewNITreeNode(subnet1, "ni3") + sg3.AddIcon(ni3) GroupNIsWithVSI(zone1, "vsi2", []TreeNodeInterface{ni2}) sg4 := NewSGTreeNode(vpc1, "sg4") - ni4 := NewNITreeNode(subnet1, sg4, "ni4") + ni4 := NewNITreeNode(subnet1, "ni4") + sg4.AddIcon(ni4) GroupNIsWithVSI(zone1, "vsi2", []TreeNodeInterface{ni2}) NewConnectivityLineTreeNode(network, ni1, i4, false, "conn1") diff --git a/pkg/drawio/iconTreeNode.go b/pkg/drawio/iconTreeNode.go index 1aa82c717..0cd07639e 100644 --- a/pkg/drawio/iconTreeNode.go +++ b/pkg/drawio/iconTreeNode.go @@ -3,7 +3,9 @@ package drawio type IconTreeNodeInterface interface { TreeNodeInterface RouterID() uint + // TODO - support multi GSs SG() SquareTreeNodeInterface + setSG(SquareTreeNodeInterface) allocateNewRouteOffset() int IsVSI() bool IsNI() bool @@ -14,6 +16,7 @@ type IconTreeNodeInterface interface { IsGateway() bool absoluteRouterGeometry() (int, int) IconSize() int + hasMiniIcon() bool } type abstractIconTreeNode struct { @@ -27,16 +30,19 @@ func newAbstractIconTreeNode(parent SquareTreeNodeInterface, name string) abstra return abstractIconTreeNode{abstractTreeNode: newAbstractTreeNode(parent, name)} } -func (tn *abstractIconTreeNode) SG() SquareTreeNodeInterface { return tn.sg } -func (tn *abstractIconTreeNode) IsIcon() bool { return true } -func (tn *abstractIconTreeNode) IsVSI() bool { return false } -func (tn *abstractIconTreeNode) IsGateway() bool { return false } -func (tn *abstractIconTreeNode) IsNI() bool { return false } -func (tn *abstractIconTreeNode) IsGroupingPoint() bool { return false } -func (tn *abstractIconTreeNode) SetTooltip(tooltip []string) { tn.tooltip = tooltip } -func (tn *abstractIconTreeNode) HasTooltip() bool { return len(tn.tooltip) > 0 } -func (tn *abstractIconTreeNode) Tooltip() string { return labels2Table(tn.tooltip) } -func (tn *abstractIconTreeNode) IconSize() int { return iconSize } +func (tn *abstractIconTreeNode) SG() SquareTreeNodeInterface { return tn.sg } +func (tn *abstractIconTreeNode) setSG(sg SquareTreeNodeInterface) { tn.sg = sg } +func (tn *abstractIconTreeNode) IsIcon() bool { return true } +func (tn *abstractIconTreeNode) IsVSI() bool { return false } +func (tn *abstractIconTreeNode) IsGateway() bool { return false } +func (tn *abstractIconTreeNode) IsNI() bool { return false } +func (tn *abstractIconTreeNode) IsGroupingPoint() bool { return false } +func (tn *abstractIconTreeNode) SetTooltip(tooltip []string) { tn.tooltip = tooltip } +func (tn *abstractIconTreeNode) HasTooltip() bool { return len(tn.tooltip) > 0 } +func (tn *abstractIconTreeNode) Tooltip() string { return labels2Table(tn.tooltip) } +func (tn *abstractIconTreeNode) IconSize() int { return iconSize } +func (tn *abstractIconTreeNode) hasMiniIcon() bool { return false } +func (tn *abstractIconTreeNode) MiniIconID() uint { return tn.id + miniIconID } var offsets = []int{ 0, @@ -75,23 +81,15 @@ type NITreeNode struct { vsi string } -func NewNITreeNode(parent SquareTreeNodeInterface, sg *SGTreeNode, name string) *NITreeNode { +func NewNITreeNode(parent SquareTreeNodeInterface, name string) *NITreeNode { ni := NITreeNode{abstractIconTreeNode: newAbstractIconTreeNode(parent, name)} parent.addIconTreeNode(&ni) - if sg != nil { - ni.SetSG(sg) - } return &ni } -func (tn *NITreeNode) SetSG(sg *SGTreeNode) { - sg.addIconTreeNode(tn) - tn.sg = sg -} -func (tn *NITreeNode) VsiID() uint { return tn.id + niVsiID } + func (tn *NITreeNode) FipID() uint { return tn.id + niFipID } -func (tn *NITreeNode) SetVsi(vsi string) { tn.vsi = vsi } -func (tn *NITreeNode) Vsi() string { return tn.vsi } -func (tn *NITreeNode) HasVsi() bool { return tn.Vsi() != "" } +func (tn *NITreeNode) setVsi(vsi string) { tn.vsi = vsi } +func (tn *NITreeNode) hasMiniIcon() bool { return tn.vsi != "" } func (tn *NITreeNode) SetFIP(fip string) { tn.floatingIP = fip } func (tn *NITreeNode) Fip() string { return tn.floatingIP } func (tn *NITreeNode) HasFip() bool { return tn.Fip() != "" } @@ -104,6 +102,22 @@ func (tn *NITreeNode) absoluteRouterGeometry() (x, y int) { return x + fipXOffset, y + fipYOffset } +// /////////////////////////////////////////// +type ResIPTreeNode struct { + abstractIconTreeNode + vpe string +} + +func NewResIPTreeNode(parent SquareTreeNodeInterface, name string) *ResIPTreeNode { + rip := ResIPTreeNode{abstractIconTreeNode: newAbstractIconTreeNode(parent, name)} + parent.addIconTreeNode(&rip) + return &rip +} + +func (tn *ResIPTreeNode) setVpe(vpe string) { tn.vpe = vpe } +func (tn *ResIPTreeNode) hasMiniIcon() bool { return tn.vpe != "" } +func (tn *ResIPTreeNode) Label() string { return labels2Table([]string{tn.name, tn.vpe}) } + // /////////////////////////////////////////// type GatewayTreeNode struct { abstractIconTreeNode @@ -136,11 +150,11 @@ type VsiTreeNode struct { func GroupNIsWithVSI(parent SquareTreeNodeInterface, name string, nis []TreeNodeInterface) { switch { case len(nis) == 1: - nis[0].(*NITreeNode).SetVsi(name) + nis[0].(*NITreeNode).setVsi(name) case len(nis) > 1: vsi := newVsiTreeNode(parent, name, nis) for _, ni := range nis { - newVsiLineTreeNode(parent, vsi, ni.(*NITreeNode)) + newLogicalLineTreeNode(parent, vsi, ni.(IconTreeNodeInterface)) } } } @@ -148,7 +162,6 @@ func GroupNIsWithVSI(parent SquareTreeNodeInterface, name string, nis []TreeNode func newVsiTreeNode(parent SquareTreeNodeInterface, name string, nis []TreeNodeInterface) *VsiTreeNode { vsi := &VsiTreeNode{abstractIconTreeNode: newAbstractIconTreeNode(parent, name), nis: nis} parent.addIconTreeNode(vsi) - parent.setHasVSIs() return vsi } @@ -169,6 +182,30 @@ func (tn *VsiTreeNode) DrawioParent() TreeNodeInterface { func (tn *VsiTreeNode) IsVSI() bool { return true } +// /////////////////////////////////////////// +type VpeTreeNode struct { + abstractIconTreeNode + resIPs []TreeNodeInterface +} + +func GroupResIPsWithVpe(parent SquareTreeNodeInterface, name string, resIPs []TreeNodeInterface) { + switch { + case len(resIPs) == 1: + resIPs[0].(*ResIPTreeNode).setVpe(name) + case len(resIPs) > 1: + vpe := newVpeTreeNode(parent, name, resIPs) + for _, resIP := range resIPs { + newLogicalLineTreeNode(parent, vpe, resIP.(IconTreeNodeInterface)) + } + } +} + +func newVpeTreeNode(parent SquareTreeNodeInterface, name string, resIPs []TreeNodeInterface) *VpeTreeNode { + vpe := &VpeTreeNode{abstractIconTreeNode: newAbstractIconTreeNode(parent, name), resIPs: resIPs} + parent.addIconTreeNode(vpe) + return vpe +} + // /////////////////////////////////////////// // GroupPointTreeNode is an icon for grouping, see GroupSquareTreeNode for details // the connection to the group will be to the group point diff --git a/pkg/drawio/layout.go b/pkg/drawio/layout.go index 27dacbe40..787bbe011 100644 --- a/pkg/drawio/layout.go +++ b/pkg/drawio/layout.go @@ -40,9 +40,9 @@ const ( fipXOffset = -70 fipYOffset = 40 - vsiXOffset = 30 - vsiYOffset = -10 - vsiIconSize = 40 + miniIconXOffset = 30 + miniIconYOffset = -10 + miniIconSize = 40 vsiOneRowYOffset = 90 vsiMultiRowYOffset = subnetHeight / 2 @@ -98,9 +98,9 @@ func canShareCell(i1, i2 IconTreeNodeInterface) bool { return true case i1.SG() != i2.SG(): return false - case !i1.IsNI() || !i2.IsNI(): - return true - case i1.(*NITreeNode).HasFip() || i2.(*NITreeNode).HasFip(): + case i1.IsNI() && i1.(*NITreeNode).HasFip(): + return false + case i2.IsNI() && i2.(*NITreeNode).HasFip(): return false } return true @@ -136,35 +136,38 @@ func sortGroupSquareBySize(groups []SquareTreeNodeInterface) []SquareTreeNodeInt // - else if all the NIs in the group not in a bigger group - its visibility is square // - else if all the NIs in the group are in one bigger group - its visibility is innerSquare // - else its visibility is connectedPoint -func (ly *layoutS) calcGroupsVisibility(subnet SquareTreeNodeInterface) { +func calcGroupsVisibility(subnet SquareTreeNodeInterface) { sortedBySizeGroups := sortGroupSquareBySize(subnet.(*SubnetTreeNode).groupSquares) - iconSquareGroups := map[IconTreeNodeInterface]map[SquareTreeNodeInterface]bool{} + iconShownSquareGroups := map[IconTreeNodeInterface]map[SquareTreeNodeInterface]bool{} for _, groupS := range sortedBySizeGroups { group := groupS.(*GroupSquareTreeNode) - if len(group.groupedIcons) == len(subnet.(*SubnetTreeNode).NIs()) { - group.setVisibility(theSubnet) - continue - } groupedIconsFormerGroups := map[SquareTreeNodeInterface]bool{} + hasIconOutsideAGroup := false for _, icon := range group.groupedIcons { - for g := range iconSquareGroups[icon] { + if len(iconShownSquareGroups[icon]) == 0 { + hasIconOutsideAGroup = true + } + for g := range iconShownSquareGroups[icon] { groupedIconsFormerGroups[g] = true } } - if len(groupedIconsFormerGroups) >= 2 { - group.setVisibility(connectedPoint) - continue - } - if len(groupedIconsFormerGroups) == 0 { + switch { + case len(group.groupedIcons) == len(subnet.(*SubnetTreeNode).nonGroupingIcons()): + group.setVisibility(theSubnet) + case len(groupedIconsFormerGroups) == 0: group.setVisibility(square) - } else { + case len(groupedIconsFormerGroups) == 1 && !hasIconOutsideAGroup: group.setVisibility(innerSquare) + default: + group.setVisibility(connectedPoint) } - for _, icon := range group.groupedIcons { - if _, ok := iconSquareGroups[icon]; !ok { - iconSquareGroups[icon] = map[SquareTreeNodeInterface]bool{} + if !group.NotShownInDrawio() { + for _, icon := range group.groupedIcons { + if _, ok := iconShownSquareGroups[icon]; !ok { + iconShownSquareGroups[icon] = map[SquareTreeNodeInterface]bool{} + } + iconShownSquareGroups[icon][group] = true } - iconSquareGroups[icon][group] = true } } } @@ -172,7 +175,7 @@ func (ly *layoutS) calcGroupsVisibility(subnet SquareTreeNodeInterface) { // 2. getSubnetIconsOrder() - set the order of the icons to be displayed in the subnet // returns [][]IconTreeNodeInterface - the order of the icons. -func (ly *layoutS) getSubnetIconsOrder(subnet SquareTreeNodeInterface) [][]IconTreeNodeInterface { +func getSubnetIconsOrder(subnet SquareTreeNodeInterface) [][]IconTreeNodeInterface { sortedBySizeGroups := sortGroupSquareBySize(subnet.(*SubnetTreeNode).groupSquares) iconOuterGroup := map[IconTreeNodeInterface]SquareTreeNodeInterface{} iconInnerGroup := map[IconTreeNodeInterface]SquareTreeNodeInterface{} @@ -210,11 +213,9 @@ func (ly *layoutS) getSubnetIconsOrder(subnet SquareTreeNodeInterface) [][]IconT } // add the rest of the icons in the subnet nonGroupedIcons := []IconTreeNodeInterface{} - for _, icon := range subnet.IconTreeNodes() { + for _, icon := range subnet.(*SubnetTreeNode).nonGroupingIcons() { if _, ok := iconOuterGroup[icon]; !ok { - if icon.IsNI() { - nonGroupedIcons = append(nonGroupedIcons, icon) - } + nonGroupedIcons = append(nonGroupedIcons, icon) } } iconsOrder = append(iconsOrder, nonGroupedIcons) @@ -239,8 +240,8 @@ func (ly *layoutS) layoutGroupIcons(group []IconTreeNodeInterface, rowIndex, col iconInCurrentCell = icon } else { icon.setLocation(iconInCurrentCell.Location().copy()) - iconInCurrentCell.Location().xOffset = iconSize - icon.Location().xOffset = -iconSize + iconInCurrentCell.Location().xOffset = -iconSize + icon.Location().xOffset = iconSize rowIndex++ iconInCurrentCell = nil } @@ -269,8 +270,8 @@ func (ly *layoutS) layoutSubnetsIcons() { ly.setDefaultLocation(zone, rowIndex, colIndex) for _, subnet := range zone.(*ZoneTreeNode).subnets { ly.setDefaultLocation(subnet, rowIndex, colIndex) - ly.calcGroupsVisibility(subnet) - groups := ly.getSubnetIconsOrder(subnet) + calcGroupsVisibility(subnet) + groups := getSubnetIconsOrder(subnet) for _, group := range groups { rowIndex, colIndex = ly.layoutGroupIcons(group, rowIndex, colIndex) } @@ -351,7 +352,7 @@ func (ly *layoutS) resolvePublicNetworkLocations() { ly.network.(*NetworkTreeNode).publicNetwork.setLocation(pnl) } -func (ly *layoutS) setGroupSquareOffsets(tn SquareTreeNodeInterface) { +func setGroupSquareOffsets(tn SquareTreeNodeInterface) { if tn.(*GroupSquareTreeNode).visibility == square { tn.Location().xOffset = groupBorderWidth tn.Location().yOffset = groupTopBorderWidth @@ -366,7 +367,7 @@ func (ly *layoutS) setGroupSquareOffsets(tn SquareTreeNodeInterface) { } } -func (*layoutS) resolveSquareLocation(tn SquareTreeNodeInterface, internalBorders int, addExternalBorders bool) { +func resolveSquareLocation(tn SquareTreeNodeInterface, internalBorders int, addExternalBorders bool) { nl := mergeLocations(locations(getAllNodes(tn))) for i := 0; i < internalBorders; i++ { nl = newLocation(nl.prevRow(), nl.nextRow(), nl.prevCol(), nl.nextCol()) @@ -386,23 +387,23 @@ func (*layoutS) resolveSquareLocation(tn SquareTreeNodeInterface, internalBorder func (ly *layoutS) setSquaresLocations() { for _, cloud := range ly.network.(*NetworkTreeNode).clouds { - ly.resolveSquareLocation(cloud, cloudToSubnetDepth, true) + resolveSquareLocation(cloud, cloudToSubnetDepth, true) for _, vpc := range cloud.(*CloudTreeNode).vpcs { - ly.resolveSquareLocation(vpc, vpcToSubnetDepth, true) + resolveSquareLocation(vpc, vpcToSubnetDepth, true) for _, zone := range vpc.(*VpcTreeNode).zones { - ly.resolveSquareLocation(zone, zoneToSubnetDepth, true) + resolveSquareLocation(zone, zoneToSubnetDepth, true) for _, subnet := range zone.(*ZoneTreeNode).subnets { - ly.resolveSquareLocation(subnet, 0, true) + resolveSquareLocation(subnet, 0, true) for _, groupSquare := range subnet.(*SubnetTreeNode).groupSquares { - ly.resolveSquareLocation(groupSquare, 0, false) - ly.setGroupSquareOffsets(groupSquare) + resolveSquareLocation(groupSquare, 0, false) + setGroupSquareOffsets(groupSquare) } } } } } ly.resolvePublicNetworkLocations() - ly.resolveSquareLocation(ly.network, 1, false) + resolveSquareLocation(ly.network, 1, false) } // //////////////////////////////////////////////////////////////////////////////////////// @@ -468,7 +469,7 @@ func (ly *layoutS) setVpcIconsLocations(vpc SquareTreeNodeInterface) { // every connection to a group square is done via a grouping point // calcGroupingIconLocation() calc the raw and column of a group point depend of the locations of the group, and the colleague group // the group points are located in the column outside the subnet. in the left or in the right. depend on the colleague location -func (ly *layoutS) calcGroupingIconLocation(location, collLocation *Location) (r *row, c *col) { +func calcGroupingIconLocation(location, collLocation *Location) (r *row, c *col) { switch { case location.lastRow.index < collLocation.firstRow.index: r = location.lastRow @@ -508,7 +509,7 @@ func (ly *layoutS) setGroupingIconLocations() { colleague := gIcon.getColleague() parentLocation := parent.Location() colleagueParentLocation := colleague.Parent().Location() - r, c := ly.calcGroupingIconLocation(parentLocation, colleagueParentLocation) + r, c := calcGroupingIconLocation(parentLocation, colleagueParentLocation) gIcon.setLocation(newCellLocation(r, c)) gIcon.Location().yOffset = groupedIconsDistance * iconsInCell[cell{r, c}] @@ -534,7 +535,7 @@ func (ly *layoutS) setGroupingIconLocations() { // if vsi icon shares by several subnet - we put it below one of the subnets // else we put it inside the subnet // gateway we put at the top -func (ly *layoutS) setZoneIconsLocations(zone SquareTreeNodeInterface) { +func setZoneIconsLocations(zone SquareTreeNodeInterface) { for _, icon := range zone.IconTreeNodes() { if icon.IsVSI() { vsiIcon := icon.(*VsiTreeNode) @@ -574,7 +575,7 @@ func (ly *layoutS) setIconsLocations() { for _, cloud := range ly.network.(*NetworkTreeNode).clouds { for _, vpc := range cloud.(*CloudTreeNode).vpcs { for _, zone := range vpc.(*VpcTreeNode).zones { - ly.setZoneIconsLocations(zone) + setZoneIconsLocations(zone) } ly.setVpcIconsLocations(vpc) } diff --git a/pkg/drawio/lineTreeNode.go b/pkg/drawio/lineTreeNode.go index 830e88595..e017ac400 100644 --- a/pkg/drawio/lineTreeNode.go +++ b/pkg/drawio/lineTreeNode.go @@ -67,14 +67,13 @@ func (tn *abstractLineTreeNode) addPoint(x, y int) { } // //////////////////////////////////////////////////////////////// -type VsiLineTreeNode struct { +type LogicalLineTreeNode struct { abstractLineTreeNode } -func newVsiLineTreeNode(network SquareTreeNodeInterface, vsi, ni IconTreeNodeInterface) *VsiLineTreeNode { - conn := VsiLineTreeNode{abstractLineTreeNode{abstractTreeNode: newAbstractTreeNode(network, ""), src: vsi, dst: ni}} +func newLogicalLineTreeNode(network SquareTreeNodeInterface, i1, i2 IconTreeNodeInterface) { + conn := LogicalLineTreeNode{abstractLineTreeNode{abstractTreeNode: newAbstractTreeNode(network, ""), src: i1, dst: i2}} network.addLineTreeNode(&conn) - return &conn } // //////////////////////////////////////////////////////////////// diff --git a/pkg/drawio/squareTreeNode.go b/pkg/drawio/squareTreeNode.go index 1ccf6e195..64def812b 100644 --- a/pkg/drawio/squareTreeNode.go +++ b/pkg/drawio/squareTreeNode.go @@ -8,8 +8,6 @@ type SquareTreeNodeInterface interface { IconTreeNodes() []IconTreeNodeInterface TagID() uint DecoreID() uint - HasVSIs() bool - setHasVSIs() IsGroupingSquare() bool } @@ -17,7 +15,6 @@ type abstractSquareTreeNode struct { abstractTreeNode elements []IconTreeNodeInterface connections []LineTreeNodeInterface - hasVSIs bool } func newAbstractSquareTreeNode(parent TreeNodeInterface, name string) abstractSquareTreeNode { @@ -38,13 +35,6 @@ func (tn *abstractSquareTreeNode) IsSquare() bool { return true } func (tn *abstractSquareTreeNode) TagID() uint { return tn.id + tagID } func (tn *abstractSquareTreeNode) DecoreID() uint { return tn.id + decoreID } -func (tn *abstractSquareTreeNode) HasVSIs() bool { return tn.hasVSIs } -func (tn *abstractSquareTreeNode) setHasVSIs() { - tn.hasVSIs = true - if tn.Parent() != nil && tn.Parent().IsSquare() { - tn.Parent().(SquareTreeNodeInterface).setHasVSIs() - } -} func (tn *abstractSquareTreeNode) IsGroupingSquare() bool { return false } func calculateSquareGeometry(tn SquareTreeNodeInterface) { @@ -164,6 +154,11 @@ func NewSGTreeNode(parent *VpcTreeNode, name string) *SGTreeNode { func (tn *SGTreeNode) children() ([]SquareTreeNodeInterface, []IconTreeNodeInterface, []LineTreeNodeInterface) { return tn.partialSgs, tn.elements, tn.connections } +func (tn *SGTreeNode) AddIcon(icon IconTreeNodeInterface) { + tn.addIconTreeNode(icon) + icon.setSG(tn) +} + func (tn *SGTreeNode) NotShownInDrawio() bool { return true } /////////////////////////////////////////////////////////////////////// @@ -208,10 +203,10 @@ func (tn *SubnetTreeNode) Label() string { func (tn *SubnetTreeNode) SetACL(acl string) { tn.acl = acl } -func (tn *SubnetTreeNode) NIs() []IconTreeNodeInterface { +func (tn *SubnetTreeNode) nonGroupingIcons() []IconTreeNodeInterface { nis := []IconTreeNodeInterface{} for _, icon := range tn.elements { - if icon.IsNI() { + if !icon.IsGroupingPoint() { nis = append(nis, icon) } } diff --git a/pkg/drawio/styles.go b/pkg/drawio/styles.go index 822e167bc..a891ce1e3 100644 --- a/pkg/drawio/styles.go +++ b/pkg/drawio/styles.go @@ -7,32 +7,19 @@ import ( ) const ( - vsiStyle = "shape=image;aspect=fixed;image=data:image/svg+xml,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0OSA0OSI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOiMxOTgwMzg7fS5jbHMtMntmaWxsOiNmZmY7fS5jbHMtM3tmaWxsOm5vbmU7fTwvc3R5bGU+PC9kZWZzPjxyZWN0IGNsYXNzPSJjbHMtMSIgeD0iMC41IiB5PSIwLjUiIHdpZHRoPSI0OCIgaGVpZ2h0PSI0OCIvPjxjaXJjbGUgY2xhc3M9ImNscy0yIiBjeD0iMTguODgiIGN5PSIyOC44OCIgcj0iMC42MyIvPjxyZWN0IGNsYXNzPSJjbHMtMiIgeD0iMTUuNzUiIHk9IjE4LjI1IiB3aWR0aD0iMi41IiBoZWlnaHQ9IjEuMjUiLz48cmVjdCBjbGFzcz0iY2xzLTIiIHg9IjE5LjUiIHk9IjE4LjI1IiB3aWR0aD0iMi41IiBoZWlnaHQ9IjEuMjUiLz48cmVjdCBjbGFzcz0iY2xzLTIiIHg9IjIzLjI1IiB5PSIxOC4yNSIgd2lkdGg9IjIuNSIgaGVpZ2h0PSIxLjI1Ii8+PHJlY3QgY2xhc3M9ImNscy0yIiB4PSIyNyIgeT0iMTguMjUiIHdpZHRoPSIyLjUiIGhlaWdodD0iMS4yNSIvPjxyZWN0IGNsYXNzPSJjbHMtMiIgeD0iMzAuNzUiIHk9IjE4LjI1IiB3aWR0aD0iMi41IiBoZWlnaHQ9IjEuMjUiLz48cGF0aCBjbGFzcz0iY2xzLTIiIGQ9Ik0zMiwzMkgxN2ExLjI1LDEuMjUsMCwwLDEtMS4yNS0xLjI1VjI3QTEuMjUsMS4yNSwwLDAsMSwxNywyNS43NUgzMkExLjI1LDEuMjUsMCwwLDEsMzMuMjUsMjd2My43NUExLjI1LDEuMjUsMCwwLDEsMzIsMzJaTTE3LDI3djMuNzVIMzJWMjdaIi8+PHJlY3QgY2xhc3M9ImNscy0zIiB4PSIxNC41IiB5PSIxNC41IiB3aWR0aD0iMjAiIGhlaWdodD0iMjAiLz48cmVjdCBjbGFzcz0iY2xzLTIiIHg9IjE1Ljc1IiB5PSIyMiIgd2lkdGg9IjE3LjUiIGhlaWdodD0iMS4yNSIvPjwvc3ZnPg==;fontFamily=IBM Plex Sans;fontSource=fonts%2FIBMPlexSans-Regular.woff;fontSize=14;spacingTop=-7;labelPosition=center;verticalLabelPosition=bottom;align=center;verticalAlign=top;" - fipStyle = "shape=image;aspect=fixed;image=data:image/svg+xml,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0OSA0OSI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOiMxMTkyZTg7fS5jbHMtMntmaWxsOiNmZmY7fS5jbHMtM3tmaWxsOm5vbmU7fTwvc3R5bGU+PC9kZWZzPjxyZWN0IGNsYXNzPSJjbHMtMSIgeD0iMC41IiB5PSIwLjkyIiB3aWR0aD0iNDgiIGhlaWdodD0iNDcuMTYiIHJ4PSI4Ii8+PHBhdGggY2xhc3M9ImNscy0yIiBkPSJNMzAuMTIsMjEuNDNhMy4xMywzLjEzLDAsMCwwLTMuMDYsMi40NkgyMS45NGEzLjA3LDMuMDcsMCwxLDAsMCwxLjIyaDUuMTJhMy4xMiwzLjEyLDAsMSwwLDMuMDYtMy42OFptMCw0LjkxQTEuODQsMS44NCwwLDEsMSwzMiwyNC41LDEuODUsMS44NSwwLDAsMSwzMC4xMiwyNi4zNFoiLz48cmVjdCBjbGFzcz0iY2xzLTMiIHg9IjE0LjUiIHk9IjE0LjY3IiB3aWR0aD0iMjAiIGhlaWdodD0iMTkuNjUiLz48L3N2Zz4=;fontFamily=IBM Plex Sans;fontSource=fonts%2FIBMPlexSans-Regular.woff;fontSize=14;labelPosition=center;verticalLabelPosition=bottom;align=center;verticalAlign=top;spacingTop=-7;" + niStyle = "shape=image;aspect=fixed;image=data:image/svg+xml,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0OSA0OSI+CjxkZWZzPgo8c3R5bGU+LmNscy0xe2ZpbGw6I2VlNTM5Njt9LmNscy0ye2ZpbGw6bm9uZTt9LmNscy0ze2ZpbGw6I2ZmZjt9PC9zdHlsZT4KPC9kZWZzPg0KPHJlY3QgY2xhc3M9ImNscy0xIiB4PSIwLjUiIHk9IjAuNSIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ii8+CjxyZWN0IGNsYXNzPSJjbHMtMiIgeD0iMTQuNSIgeT0iMTQuNSIgd2lkdGg9IjIwIiBoZWlnaHQ9IjIwIi8+DQo8dGV4dCBmb250LXNpemU9IjMwIiBmaWxsPSJ3aGl0ZSIgeD0iOCIgeT0iMzUiPk5JPC90ZXh0Pgo8L3N2Zz4=;fontFamily=IBM Plex Sans;fontSource=fonts%2FIBMPlexSans-Regular.woff;fontSize=14;labelPosition=center;verticalLabelPosition=bottom;align=center;verticalAlign=top;spacingTop=-7;" + vsiStyle = "shape=image;aspect=fixed;image=data:image/svg+xml,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0OSA0OSI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOiMxOTgwMzg7fS5jbHMtMntmaWxsOiNmZmY7fS5jbHMtM3tmaWxsOm5vbmU7fTwvc3R5bGU+PC9kZWZzPjxyZWN0IGNsYXNzPSJjbHMtMSIgeD0iMC41IiB5PSIwLjUiIHdpZHRoPSI0OCIgaGVpZ2h0PSI0OCIvPjxjaXJjbGUgY2xhc3M9ImNscy0yIiBjeD0iMTguODgiIGN5PSIyOC44OCIgcj0iMC42MyIvPjxyZWN0IGNsYXNzPSJjbHMtMiIgeD0iMTUuNzUiIHk9IjE4LjI1IiB3aWR0aD0iMi41IiBoZWlnaHQ9IjEuMjUiLz48cmVjdCBjbGFzcz0iY2xzLTIiIHg9IjE5LjUiIHk9IjE4LjI1IiB3aWR0aD0iMi41IiBoZWlnaHQ9IjEuMjUiLz48cmVjdCBjbGFzcz0iY2xzLTIiIHg9IjIzLjI1IiB5PSIxOC4yNSIgd2lkdGg9IjIuNSIgaGVpZ2h0PSIxLjI1Ii8+PHJlY3QgY2xhc3M9ImNscy0yIiB4PSIyNyIgeT0iMTguMjUiIHdpZHRoPSIyLjUiIGhlaWdodD0iMS4yNSIvPjxyZWN0IGNsYXNzPSJjbHMtMiIgeD0iMzAuNzUiIHk9IjE4LjI1IiB3aWR0aD0iMi41IiBoZWlnaHQ9IjEuMjUiLz48cGF0aCBjbGFzcz0iY2xzLTIiIGQ9Ik0zMiwzMkgxN2ExLjI1LDEuMjUsMCwwLDEtMS4yNS0xLjI1VjI3QTEuMjUsMS4yNSwwLDAsMSwxNywyNS43NUgzMkExLjI1LDEuMjUsMCwwLDEsMzMuMjUsMjd2My43NUExLjI1LDEuMjUsMCwwLDEsMzIsMzJaTTE3LDI3djMuNzVIMzJWMjdaIi8+PHJlY3QgY2xhc3M9ImNscy0zIiB4PSIxNC41IiB5PSIxNC41IiB3aWR0aD0iMjAiIGhlaWdodD0iMjAiLz48cmVjdCBjbGFzcz0iY2xzLTIiIHg9IjE1Ljc1IiB5PSIyMiIgd2lkdGg9IjE3LjUiIGhlaWdodD0iMS4yNSIvPjwvc3ZnPg==;fontFamily=IBM Plex Sans;fontSource=fonts%2FIBMPlexSans-Regular.woff;fontSize=14;spacingTop=-7;labelPosition=center;verticalLabelPosition=bottom;align=center;verticalAlign=top;" + resIPStyle = "shape=image;aspect=fixed;image=data:image/svg+xml,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0OSA0OSI+CjxkZWZzPgo8c3R5bGU+LmNscy0xe2ZpbGw6I2VlNTM5Njt9LmNscy0ye2ZpbGw6bm9uZTt9LmNscy0ze2ZpbGw6I2ZmZjt9PC9zdHlsZT4KPC9kZWZzPg0KPHJlY3QgY2xhc3M9ImNscy0xIiB4PSIwLjUiIHk9IjAuNSIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ii8+CjxyZWN0IGNsYXNzPSJjbHMtMiIgeD0iMTQuNSIgeT0iMTQuNSIgd2lkdGg9IjIwIiBoZWlnaHQ9IjIwIi8+DQo8dGV4dCBmb250LXNpemU9IjIwIiBmaWxsPSJ3aGl0ZSIgeD0iNSIgeT0iMzIiPnJlc0lQPC90ZXh0Pgo8L3N2Zz4=;fontFamily=IBM Plex Sans;fontSource=fonts%2FIBMPlexSans-Regular.woff;fontSize=14;labelPosition=center;verticalLabelPosition=bottom;align=center;verticalAlign=top;spacingTop=-7;" + vpeStyle = "shape=image;aspect=fixed;image=data:image/svg+xml,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0OSA0OSI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOiMxMTkyZTg7fS5jbHMtMntmaWxsOiNmZmY7fS5jbHMtM3tmaWxsOm5vbmU7fTwvc3R5bGU+PC9kZWZzPjxyZWN0IGNsYXNzPSJjbHMtMSIgeD0iMC41IiB5PSIwLjUiIHdpZHRoPSI0OCIgaGVpZ2h0PSI0OCIvPjxwYXRoIGlkPSJ2cGNfZ3JhZGllbnRfYm90dG9tIiBkYXRhLW5hbWU9InZwYyBncmFkaWVudCBib3R0b20iIGNsYXNzPSJjbHMtMiIgZD0iTTI3LDMxLjM4SDE4Ljg4YTEuMjcsMS4yNywwLDAsMS0xLjI2LTEuMjVWMjJoMS4yNnY4LjEzSDI3WiIvPjxwYXRoIGlkPSJ2cGNfZ3JhZGllbnRfdG9wIiBkYXRhLW5hbWU9InZwYyBncmFkaWVudCB0b3AiIGNsYXNzPSJjbHMtMiIgZD0iTTMwLjEyLDI3aDEuMjZWMTguODhhMS4yNiwxLjI2LDAsMCwwLTEuMjYtMS4yNUgyMnYxLjI1aDguMTJaIi8+PHBhdGggaWQ9ImVuZHBvaW50cyIgY2xhc3M9ImNscy0yIiBkPSJNMjkuMTIsMjguMjVsLTIuNS0yLjVBMi4yNiwyLjI2LDAsMCwwLDI3LDI0LjUsMi41MSwyLjUxLDAsMCwwLDI0LjUsMjJhMi4xOSwyLjE5LDAsMCwwLTEuMjUuMzhsLTIuNS0yLjVWMTUuNzVoLTV2NWg0LjEzbDIuNSwyLjVBMi4yNiwyLjI2LDAsMCwwLDIyLDI0LjUsMi41MSwyLjUxLDAsMCwwLDI0LjUsMjdhMi4yNiwyLjI2LDAsMCwwLDEuMjUtLjM4bDIuNSwyLjV2NC4xM2g1di01Wk0xOS41LDE5LjVIMTdWMTdoMi41Wm01LDYuMjVhMS4yNSwxLjI1LDAsMSwxLDEuMjUtMS4yNUExLjI1LDEuMjUsMCwwLDEsMjQuNSwyNS43NVpNMzIsMzJIMjkuNVYyOS41SDMyWiIvPjxyZWN0IGNsYXNzPSJjbHMtMyIgeD0iMTQuNSIgeT0iMTQuNSIgd2lkdGg9IjIwIiBoZWlnaHQ9IjIwIi8+PC9zdmc+;fontSize=14;fontFamily=IBM Plex Sans;fontSource=fonts%2FIBMPlexSans-Regular.woff;spacingTop=-7;labelPosition=center;verticalLabelPosition=bottom;align=center;verticalAlign=top;" + fipStyle = "shape=image;aspect=fixed;image=data:image/svg+xml,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0OSA0OSI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOiMxMTkyZTg7fS5jbHMtMntmaWxsOiNmZmY7fS5jbHMtM3tmaWxsOm5vbmU7fTwvc3R5bGU+PC9kZWZzPjxyZWN0IGNsYXNzPSJjbHMtMSIgeD0iMC41IiB5PSIwLjkyIiB3aWR0aD0iNDgiIGhlaWdodD0iNDcuMTYiIHJ4PSI4Ii8+PHBhdGggY2xhc3M9ImNscy0yIiBkPSJNMzAuMTIsMjEuNDNhMy4xMywzLjEzLDAsMCwwLTMuMDYsMi40NkgyMS45NGEzLjA3LDMuMDcsMCwxLDAsMCwxLjIyaDUuMTJhMy4xMiwzLjEyLDAsMSwwLDMuMDYtMy42OFptMCw0LjkxQTEuODQsMS44NCwwLDEsMSwzMiwyNC41LDEuODUsMS44NSwwLDAsMSwzMC4xMiwyNi4zNFoiLz48cmVjdCBjbGFzcz0iY2xzLTMiIHg9IjE0LjUiIHk9IjE0LjY3IiB3aWR0aD0iMjAiIGhlaWdodD0iMTkuNjUiLz48L3N2Zz4=;fontFamily=IBM Plex Sans;fontSource=fonts%2FIBMPlexSans-Regular.woff;fontSize=14;labelPosition=center;verticalLabelPosition=bottom;align=center;verticalAlign=top;spacingTop=-7;" + connStyleFormat = "endArrow=%s;html=1;fontSize=16;fontColor=#4376BB;strokeWidth=2;endFill=1;rounded=0;startArrow=%s;%sstartFill=1;" + connRouteredCollor = "strokeColor=#007FFF;" + ovalEndEdge = "oval" errorEndEdge = "block" noneEndEdge = "none" ) -func connectivityStyle(con *ConnectivityTreeNode) string { - startArrow, endArrow := ovalEndEdge, ovalEndEdge - strokeColor := "" - if con.directed { - endArrow = errorEndEdge - } - if con.Src().IsGroupingPoint() && !con.Src().(*GroupPointTreeNode).hasShownSquare() { - startArrow = noneEndEdge - } - if con.Dst().IsGroupingPoint() && !con.Dst().(*GroupPointTreeNode).hasShownSquare() { - endArrow = noneEndEdge - } - if con.router != nil { - strokeColor = "strokeColor=#007FFF;" - } - styleFormat := "endArrow=%s;html=1;fontSize=16;fontColor=#4376BB;strokeWidth=2;endFill=1;rounded=0;startArrow=%s;%sstartFill=1;" - return fmt.Sprintf(styleFormat, endArrow, startArrow, strokeColor) -} - var styles = map[reflect.Type]string{ reflect.TypeOf(PublicNetworkTreeNode{}): "rounded=0;whiteSpace=wrap;html=1;fontFamily=IBM Plex Sans;fontSource=fonts%2FIBMPlexSans-Regular.woff;fontSize=14;spacingBottom=-28;spacingTop=0;labelPosition=-100;verticalLabelPosition=top;align=center;verticalAlign=bottom;spacingLeft=9;spacing=0;expand=0;recursiveResize=0;spacingRight=0;container=1;collapsible=0;strokeColor=#1192E8;fillColor=none;", reflect.TypeOf(CloudTreeNode{}): "rounded=0;whiteSpace=wrap;html=1;fontFamily=IBM Plex Sans;fontSource=fonts%2FIBMPlexSans-Regular.woff;fontSize=14;spacingBottom=-28;spacingTop=0;labelPosition=-100;verticalLabelPosition=top;align=center;verticalAlign=bottom;spacingLeft=9;spacing=0;expand=0;recursiveResize=0;spacingRight=0;container=1;collapsible=0;strokeColor=#1192E8;fillColor=none;", @@ -41,16 +28,22 @@ var styles = map[reflect.Type]string{ reflect.TypeOf(PartialSGTreeNode{}): "rounded=0;whiteSpace=wrap;html=1;fontFamily=IBM Plex Sans;fontSource=fonts%2FIBMPlexSans-Regular.woff;fontSize=14;fillColor=none;spacingBottom=-28;spacingTop=0;labelPosition=-100;verticalLabelPosition=top;align=center;verticalAlign=bottom;spacingLeft=9;spacing=0;expand=0;recursiveResize=0;spacingRight=0;container=1;collapsible=0;strokeColor=#FA4D56;strokeWidth=1;", reflect.TypeOf(SubnetTreeNode{}): "rounded=0;whiteSpace=wrap;html=1;fontFamily=IBM Plex Sans;fontSource=fonts%2FIBMPlexSans-Regular.woff;fontSize=14;spacingBottom=-28;spacingTop=0;labelPosition=-100;verticalLabelPosition=top;align=center;verticalAlign=bottom;spacingLeft=9;spacing=0;expand=0;recursiveResize=0;spacingRight=0;container=1;collapsible=0;strokeColor=#1192E8;fillColor=none;", reflect.TypeOf(GroupSquareTreeNode{}): "rounded=1;whiteSpace=wrap;html=1;fillColor=none;strokeColor=#006633;strokeWidth=1;perimeterSpacing=0;arcSize=12;", - reflect.TypeOf(NITreeNode{}): "shape=image;aspect=fixed;image=data:image/svg+xml,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0OSA0OSI+CjxkZWZzPgo8c3R5bGU+LmNscy0xe2ZpbGw6I2VlNTM5Njt9LmNscy0ye2ZpbGw6bm9uZTt9LmNscy0ze2ZpbGw6I2ZmZjt9PC9zdHlsZT4KPC9kZWZzPg0KPHJlY3QgY2xhc3M9ImNscy0xIiB4PSIwLjUiIHk9IjAuNSIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ii8+CjxyZWN0IGNsYXNzPSJjbHMtMiIgeD0iMTQuNSIgeT0iMTQuNSIgd2lkdGg9IjIwIiBoZWlnaHQ9IjIwIi8+DQo8dGV4dCBmb250LXNpemU9IjMwIiBmaWxsPSJ3aGl0ZSIgeD0iOCIgeT0iMzUiPk5JPC90ZXh0Pgo8L3N2Zz4=;fontFamily=IBM Plex Sans;fontSource=fonts%2FIBMPlexSans-Regular.woff;fontSize=14;labelPosition=center;verticalLabelPosition=bottom;align=center;verticalAlign=top;spacingTop=-7;", + reflect.TypeOf(NITreeNode{}): vsiStyle, reflect.TypeOf(VsiTreeNode{}): vsiStyle, + reflect.TypeOf(ResIPTreeNode{}): vpeStyle, + reflect.TypeOf(VpeTreeNode{}): vpeStyle, reflect.TypeOf(GroupPointTreeNode{}): "ellipse;whiteSpace=wrap;html=1;aspect=fixed;", reflect.TypeOf(UserTreeNode{}): "shape=image;aspect=fixed;image=data:image/svg+xml,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0OSA0OSI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOm5vbmU7fS5jbHMtMntmaWxsOiNmZmY7ZmlsbC1ydWxlOmV2ZW5vZGQ7fTwvc3R5bGU+PC9kZWZzPjxyZWN0IHg9IjAuNSIgeT0iMC41IiB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHJ4PSIyNCIvPjxyZWN0IGNsYXNzPSJjbHMtMSIgeD0iMTQuNSIgeT0iMTQuNSIgd2lkdGg9IjIwIiBoZWlnaHQ9IjIwIi8+PHBhdGggaWQ9IkZpbGwtMyIgY2xhc3M9ImNscy0yIiBkPSJNMzAuOCwzMy44N0gyOVYyOS41OUEyLjYzLDIuNjMsMCwwLDAsMjYuMywyN0gyMi43QTIuNjMsMi42MywwLDAsMCwyMCwyOS41OXY0LjI4SDE4LjJWMjkuNTlhNC40MSw0LjQxLDAsMCwxLDQuNS00LjI4aDMuNmE0LjQxLDQuNDEsMCwwLDEsNC41LDQuMjhaIi8+PHBhdGggaWQ9IkZpbGwtNSIgY2xhc3M9ImNscy0yIiBkPSJNMjQuNSwxNS4wNUE0LjM5LDQuMzksMCwwLDAsMjAsMTkuMzNhNC41MSw0LjUxLDAsMCwwLDksMCw0LjM5LDQuMzksMCwwLDAtNC41LTQuMjhtMCwxLjcxYTIuNTcsMi41NywwLDEsMS0yLjcsMi41NywyLjY0LDIuNjQsMCwwLDEsMi43LTIuNTciLz48L3N2Zz4=;fontFamily=IBM Plex Sans;fontSource=fonts%2FIBMPlexSans-Regular.woff;fontSize=14;labelPosition=center;verticalLabelPosition=bottom;align=center;verticalAlign=top;spacingTop=-7;", reflect.TypeOf(GatewayTreeNode{}): "shape=image;aspect=fixed;image=data:image/svg+xml,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0OSA0OSI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOiMxMTkyZTg7fS5jbHMtMntmaWxsOiNmZmY7fS5jbHMtM3tmaWxsOm5vbmU7fTwvc3R5bGU+PC9kZWZzPjxyZWN0IGNsYXNzPSJjbHMtMSIgeD0iMC41IiB5PSIwLjUiIHdpZHRoPSI0OCIgaGVpZ2h0PSI0OCIgcng9IjgiLz48cGF0aCBjbGFzcz0iY2xzLTIiIGQ9Ik0zMy41MSwyNS4zOGExLjIzLDEuMjMsMCwwLDAsMC0xLjc2TDI5Ljg5LDIwbDEuODEtMS43OWExLjI1LDEuMjUsMCwxLDAtLjU4LTIuMDksMS4yMiwxLjIyLDAsMCwwLS4zMiwxLjIyTDI5LDE5LjEybC0zLjYzLTMuNjNhMS4yMywxLjIzLDAsMCwwLTEuNzYsMEwyMCwxOS4xMWwtMS43OS0xLjgyYTEuMjQsMS4yNCwwLDEsMC0yLjA5LjU5LDEuMjIsMS4yMiwwLDAsMCwxLjIyLjMyTDE5LjEyLDIwbC0zLjYzLDMuNjNhMS4yMywxLjIzLDAsMCwwLDAsMS43NkwxOS4xMiwyOSwxNy4zNCwzMC44YTEuMjIsMS4yMiwwLDAsMC0xLjIyLjMyLDEuMjQsMS4yNCwwLDEsMCwyLjA5LjU5TDIwLDI5Ljg5bDMuNjIsMy42MmExLjIzLDEuMjMsMCwwLDAsMS43NiwwTDI5LDI5Ljg4bDEuNzksMS43OGExLjIyLDEuMjIsMCwwLDAsLjMyLDEuMjIsMS4yNCwxLjI0LDAsMSwwLC41OC0yLjA5TDI5Ljg5LDI5Wm0tOSw3LjI0TDE2LjM4LDI0LjVsOC4xMi04LjEyLDguMTIsOC4xMloiLz48cmVjdCBjbGFzcz0iY2xzLTMiIHg9IjE0LjUiIHk9IjE0LjUiIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIvPjxwYXRoIGNsYXNzPSJjbHMtMiIgZD0iTTI2LjM4LDIzLjI1SDIzLjI1VjIyYTEuMjUsMS4yNSwwLDAsMSwyLjUsMEgyN2EyLjUsMi41LDAsMCwwLTUsMHYxLjQyYTEuMjYsMS4yNiwwLDAsMC0uNjIsMS4wOHYzLjEyYTEuMjYsMS4yNiwwLDAsMCwxLjI0LDEuMjZoMy43NmExLjI2LDEuMjYsMCwwLDAsMS4yNC0xLjI2VjI0LjVBMS4yNSwxLjI1LDAsMCwwLDI2LjM4LDIzLjI1Wm0wLDQuMzdIMjIuNjJWMjQuNWgzLjc2WiIvPjwvc3ZnPg==;fontSize=14;fontFamily=IBM Plex Sans;fontSource=fonts%2FIBMPlexSans-Regular.woff;spacingTop=-7;labelPosition=center;verticalLabelPosition=bottom;align=center;verticalAlign=top;", reflect.TypeOf(InternetTreeNode{}): "shape=image;aspect=fixed;image=data:image/svg+xml,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0OSA0OSI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOiMxMTkyZTg7fS5jbHMtMntmaWxsOiNmZmY7fS5jbHMtM3tmaWxsOm5vbmU7fTwvc3R5bGU+PC9kZWZzPjxyZWN0IGNsYXNzPSJjbHMtMSIgeD0iMC41IiB5PSIwLjUiIHdpZHRoPSI0OCIgaGVpZ2h0PSI0OCIgcng9IjgiLz48cGF0aCBjbGFzcz0iY2xzLTIiIGQ9Ik0yNC41LDE1Ljc1YTguNzUsOC43NSwwLDEsMCw4Ljc1LDguNzVBOC43NSw4Ljc1LDAsMCwwLDI0LjUsMTUuNzVaTTMyLDIzLjg4SDI4LjI1YTE1LjE5LDE1LjE5LDAsMCwwLTEuNzQtNi42QTcuNSw3LjUsMCwwLDEsMzIsMjMuODhaTTI0LjUsMzJoLS40MkExMy43MiwxMy43MiwwLDAsMSwyMiwyNS4xMmg1QTEzLjYzLDEzLjYzLDAsMCwxLDI0Ljk0LDMyWk0yMiwyMy44OEExMy42MywxMy42MywwLDAsMSwyNC4wNiwxN2EzLjkzLDMuOTMsMCwwLDEsLjg0LDBBMTMuNjQsMTMuNjQsMCwwLDEsMjcsMjMuODhabS40OC02LjZhMTUuMTgsMTUuMTgsMCwwLDAtMS43Myw2LjZIMTdhNy41LDcuNSwwLDAsMSw1LjQ5LTYuNlpNMTcsMjUuMTJoMy43NWExNS4yLDE1LjIsMCwwLDAsMS43Miw2LjZBNy41Miw3LjUyLDAsMCwxLDE3LDI1LjEyWm05LjQ4LDYuNmExNS4xOSwxNS4xOSwwLDAsMCwxLjc0LTYuNkgzMkE3LjUsNy41LDAsMCwxLDI2LjUxLDMxLjcyWiIvPjxyZWN0IGlkPSJfVHJhbnNwYXJlbnRfUmVjdGFuZ2xlXyIgZGF0YS1uYW1lPSIgVHJhbnNwYXJlbnQgUmVjdGFuZ2xlICIgY2xhc3M9ImNscy0zIiB4PSIxNC41IiB5PSIxNC41IiB3aWR0aD0iMjAiIGhlaWdodD0iMjAiLz48L3N2Zz4=;fontFamily=IBM Plex Sans;fontSource=fonts%2FIBMPlexSans-Regular.woff;fontSize=14;labelPosition=center;verticalLabelPosition=bottom;align=center;verticalAlign=top;spacingTop=-7;", reflect.TypeOf(InternetServiceTreeNode{}): "shape=image;aspect=fixed;image=data:image/svg+xml,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0OSA0OSI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOiMxMTkyZTg7fS5jbHMtMntmaWxsOiNmZmY7fS5jbHMtM3tmaWxsOm5vbmU7fTwvc3R5bGU+PC9kZWZzPjxyZWN0IGNsYXNzPSJjbHMtMSIgeD0iMC41IiB5PSIwLjUiIHdpZHRoPSI0OCIgaGVpZ2h0PSI0OCIvPjxwYXRoIGNsYXNzPSJjbHMtMiIgZD0iTTMxLjg3LDIwLjc1YTYuMjUsNi4yNSwwLDAsMC0xMi4yNi4wOCw0LjY4LDQuNjgsMCwwLDAsLjgzLDkuMjloLjk0VjI4Ljg3aC0uOTRBMy40MywzLjQzLDAsMCwxLDIwLjIsMjJsLjUyLDAsLjA2LS41MmE1LDUsMCwwLDEsOS44MS0uNzFaIi8+PHJlY3QgY2xhc3M9ImNscy0zIiB4PSIxNC41IiB5PSIxNC41IiB3aWR0aD0iMjAiIGhlaWdodD0iMjAiLz48cGF0aCBjbGFzcz0iY2xzLTIiIGQ9Ik0zMS4zNywyOS41YTEuODQsMS44NCwwLDAsMC0xLjIuNDVsLTIuNTYtMS41NGMwLS4wNSwwLS4xLDAtLjE2czAtLjExLDAtLjE2bDIuNTYtMS41NGExLjg2LDEuODYsMCwwLDAsMS4yLjQ1LDEuODgsMS44OCwwLDEsMC0xLjg3LTEuODgsMS40MiwxLjQyLDAsMCwwLDAsLjM2bC0yLjQ1LDEuNDZhMS44NiwxLjg2LDAsMCwwLTEuMzQtLjU3LDEuODgsMS44OCwwLDAsMCwwLDMuNzUsMS44NSwxLjg1LDAsMCwwLDEuMzQtLjU2TDI5LjU0LDMxYTEuNDUsMS40NSwwLDAsMCwwLC4zNSwxLjg4LDEuODgsMCwxLDAsMS44Ny0xLjg3Wm0wLTVhLjYzLjYzLDAsMSwxLS42Mi42MkEuNjMuNjMsMCwwLDEsMzEuMzcsMjQuNVptLTUuNjIsNC4zN2EuNjMuNjMsMCwwLDEtLjYzLS42Mi42NC42NCwwLDAsMSwuNjMtLjYzLjYzLjYzLDAsMCwxLC42Mi42M0EuNjIuNjIsMCwwLDEsMjUuNzUsMjguODdaTTMxLjM3LDMyYS42My42MywwLDEsMSwuNjMtLjYzQS42My42MywwLDAsMSwzMS4zNywzMloiLz48L3N2Zz4=;fontSize=14;labelPosition=center;verticalLabelPosition=bottom;align=center;verticalAlign=top;fontFamily=IBM Plex Sans;fontSource=fonts%2FIBMPlexSans-Regular.woff;spacingTop=-6;", - reflect.TypeOf(VsiLineTreeNode{}): "html=1;verticalAlign=middle;startArrow=oval;startFill=1;endArrow=oval;startSize=6;strokeColor=#000000;align=center;dashed=1;strokeWidth=2;horizontal=1;labelPosition=center;verticalLabelPosition=middle;endFill=1;rounded=0;", + reflect.TypeOf(LogicalLineTreeNode{}): "html=1;verticalAlign=middle;startArrow=oval;startFill=1;endArrow=oval;startSize=6;strokeColor=#000000;align=center;dashed=1;strokeWidth=2;horizontal=1;labelPosition=center;verticalLabelPosition=middle;endFill=1;rounded=0;", // reflect.TypeOf(EndPointTreeNode{}): "shape=image;aspect=fixed;image=data:image/svg+xml,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0OSA0OSI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOiMxMTkyZTg7fS5jbHMtMntmaWxsOiNmZmY7fS5jbHMtM3tmaWxsOm5vbmU7fTwvc3R5bGU+PC9kZWZzPjxyZWN0IGNsYXNzPSJjbHMtMSIgeD0iMC41IiB5PSIwLjUiIHdpZHRoPSI0OCIgaGVpZ2h0PSI0OCIvPjxwYXRoIGlkPSJ2cGNfZ3JhZGllbnRfYm90dG9tIiBkYXRhLW5hbWU9InZwYyBncmFkaWVudCBib3R0b20iIGNsYXNzPSJjbHMtMiIgZD0iTTI3LDMxLjM4SDE4Ljg4YTEuMjcsMS4yNywwLDAsMS0xLjI2LTEuMjVWMjJoMS4yNnY4LjEzSDI3WiIvPjxwYXRoIGlkPSJ2cGNfZ3JhZGllbnRfdG9wIiBkYXRhLW5hbWU9InZwYyBncmFkaWVudCB0b3AiIGNsYXNzPSJjbHMtMiIgZD0iTTMwLjEyLDI3aDEuMjZWMTguODhhMS4yNiwxLjI2LDAsMCwwLTEuMjYtMS4yNUgyMnYxLjI1aDguMTJaIi8+PHBhdGggaWQ9ImVuZHBvaW50cyIgY2xhc3M9ImNscy0yIiBkPSJNMjkuMTIsMjguMjVsLTIuNS0yLjVBMi4yNiwyLjI2LDAsMCwwLDI3LDI0LjUsMi41MSwyLjUxLDAsMCwwLDI0LjUsMjJhMi4xOSwyLjE5LDAsMCwwLTEuMjUuMzhsLTIuNS0yLjVWMTUuNzVoLTV2NWg0LjEzbDIuNSwyLjVBMi4yNiwyLjI2LDAsMCwwLDIyLDI0LjUsMi41MSwyLjUxLDAsMCwwLDI0LjUsMjdhMi4yNiwyLjI2LDAsMCwwLDEuMjUtLjM4bDIuNSwyLjV2NC4xM2g1di01Wk0xOS41LDE5LjVIMTdWMTdoMi41Wm01LDYuMjVhMS4yNSwxLjI1LDAsMSwxLDEuMjUtMS4yNUExLjI1LDEuMjUsMCwwLDEsMjQuNSwyNS43NVpNMzIsMzJIMjkuNVYyOS41SDMyWiIvPjxyZWN0IGNsYXNzPSJjbHMtMyIgeD0iMTQuNSIgeT0iMTQuNSIgd2lkdGg9IjIwIiBoZWlnaHQ9IjIwIi8+PC9zdmc+;fontSize=14;fontFamily=IBM Plex Sans;fontSource=fonts%2FIBMPlexSans-Regular.woff;spacingTop=-7;labelPosition=center;verticalLabelPosition=bottom;align=center;verticalAlign=top;", } +var miniStyles = map[reflect.Type]string{ + reflect.TypeOf(NITreeNode{}): niStyle, + reflect.TypeOf(ResIPTreeNode{}): resIPStyle, +} var tagStyles = map[reflect.Type]string{ reflect.TypeOf(PublicNetworkTreeNode{}): "shape=image;aspect=fixed;image=data:image/svg+xml,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMjlweCIgaGVpZ2h0PSIyNnB4IiB2aWV3Qm94PSIwIDAgMjkgMjYiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUzICg3MjUyMCkgLSBodHRwczovL3NrZXRjaGFwcC5jb20gLS0+CiAgICA8dGl0bGU+UHVibGljIE5ldHdvcmsgQmxhY2s8L3RpdGxlPgogICAgPGRlc2M+Q3JlYXRlZCB3aXRoIFNrZXRjaC48L2Rlc2M+CiAgICA8ZyBpZD0iUGFnZS0xIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgICAgICA8ZyBpZD0iUHVibGljLU5ldHdvcmstQmxhY2siIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAuOTAxMTA2LCAtMC4xNzQyMzMpIiBmaWxsPSIjMDAwMDAwIj4KICAgICAgICAgICAgPGcgaWQ9IkludGVybmV0IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMS44Njc1NTksIDEwLjExMTEyMykiPgogICAgICAgICAgICAgICAgPHBhdGggZD0iTTkuOTQwMzIwMTEsMTQuMjczNTIwNyBDMTAuOTEwMDkwMywxMi40MzQ5NjI3IDExLjQ0ODI4NzQsMTAuMzk5NTE3MSAxMS41MTQyOTI3LDguMzIxNzYwMzkgTDE0Ljg5OTE4MDEsOC4zMjE3NjAzOSBDMTQuNjU3MTYwNywxMS4xNDg3MDU1IDEyLjY3NzU2NTcsMTMuNTI0ODk2NCA5Ljk0MDMyMDExLDE0LjI3MzUyMDcgTDkuOTQwMzIwMTEsMTQuMjczNTIwNyBaIE0xLjM4NzgzODAzLDguMzIxNzYwMzkgTDQuNzcyNzI1NCw4LjMyMTc2MDM5IEM0LjgzMTk2MDkyLDEwLjM5NzgyNDYgNS4zNjIyNTk5NSwxMi40MzMyNzAzIDYuMzI0MTMyMTEsMTQuMjczNTIwNyBDMy41OTU5MTI4OSwxMy41MTY5OTg0IDEuNjI3MDM2NzMsMTEuMTQzMDY0IDEuMzg3ODM4MDMsOC4zMjE3NjAzOSBMMS4zODc4MzgwMyw4LjMyMTc2MDM5IFogTTYuNDA2NDk3NywxLjU1MTk4NTY1IEM1LjQwMTc1MDMsMy40NzA2NTI2NSA0Ljg0NjYyODc3LDUuNTkyOTc3MDMgNC43ODM0NDQyMSw3Ljc1NzYxMjUgTDEuMjU0MTM0OTgsNy43NTc2MTI1IEMxLjUwNjg3MzIzLDQuODA5OTM5NzUgMy41NzA1MjYyMywyLjMzMjc2NjM0IDYuNDI0NTUwNDMsMS41NTE5ODU2NSBMNi40MDY0OTc3LDEuNTUxOTg1NjUgWiBNNS44NzI4MTM3OSw3LjE5MzQ2NDYgQzUuOTI5MjI4NTgsNC45OTYxMDg1NSA2LjU3MTc5MzAzLDIuODUzNDc0ODUgNy43MzQ1MDE4NCwwLjk4NzgzNzc2IEM3Ljk4NjExMTgsMC45NTk2MzAzNjUgOC4yMzk0MTQyMSwwLjk1OTYzMDM2NSA4LjQ5MDQ2MDAyLDAuOTg3ODM3NzYgQzkuNjY1NTgwMDksMi44NTAwODk5NiAxMC4zMTk5OTE2LDQuOTkyNzIzNjcgMTAuMzg1OTk2OSw3LjE5MzQ2NDYgTDUuODcyODEzNzksNy4xOTM0NjQ2IFogTTguMTI5NDA1MzcsMTQuNTI3Mzg3MiBDOC4wMDM2MDAzOSwxNC41MzU4NDk1IDcuODc3MjMxMjYsMTQuNTM1ODQ5NSA3Ljc1MTQyNjI4LDE0LjUyNzM4NzIgQzYuNTgyNTExODQsMTIuNjYzNDQyNiA1LjkzNDMwNTkxLDEwLjUyMDgwODkgNS44NzI4MTM3OSw4LjMyMTc2MDM5IEwxMC4zODU5OTY5LDguMzIxNzYwMzkgQzEwLjMzMDE0NjMsMTAuNTE5NjgwNiA5LjY4NzAxNzcxLDEyLjY2MjMxNDMgOC41MjQzMDg5LDE0LjUyNzM4NzIgQzguMzkyODYyNDQsMTQuNTM2NDEzNiA4LjI2MDg1MTgzLDE0LjUzNjQxMzYgOC4xMjk0MDUzNywxNC41MjczODcyIEw4LjEyOTQwNTM3LDE0LjUyNzM4NzIgWiBNMTQuODk5MTgwMSw3LjE5MzQ2NDYgTDExLjUxNDI5MjcsNy4xOTM0NjQ2IEMxMS40NDgyODc0LDUuMTE1NzA3OTEgMTAuOTEwMDkwMywzLjA4MDI2MjMgOS45NDAzMjAxMSwxLjI0MTcwNDMxIEMxMi42Nzc1NjU3LDEuOTkwMzI4NTcgMTQuNjU3MTYwNyw0LjM2NjUxOTUgMTQuODk5MTgwMSw3LjE5MzQ2NDYgTDE0Ljg5OTE4MDEsNy4xOTM0NjQ2IFogTTguMTI5NDA1MzcsMC4xMzcxMDI3MzQgQzMuNzY3NDEzODUsMC4xMzcxMDI3MzQgMC4yMzEzMzQ4NDIsMy42NzMxODE3NCAwLjIzMTMzNDg0Miw4LjAzNTE3MzI2IEMwLjIzMTMzNDg0MiwxMi4zOTcxNjQ4IDMuNzY3NDEzODUsMTUuOTMzMjQzOCA4LjEyOTQwNTM3LDE1LjkzMzI0MzggQzEyLjQ5MTM5NjksMTUuOTMzMjQzOCAxNi4wMjc0NzU5LDEyLjM5NzE2NDggMTYuMDI3NDc1OSw4LjAzNTE3MzI2IEMxNi4wMjc0NzU5LDMuNjczMTgxNzQgMTIuNDkxMzk2OSwwLjEzNzEwMjczNCA4LjEyOTQwNTM3LDAuMTM3MTAyNzM0IEw4LjEyOTQwNTM3LDAuMTM3MTAyNzM0IFoiIGlkPSJGaWxsLTEiPjwvcGF0aD4KICAgICAgICAgICAgPC9nPgogICAgICAgICAgICA8ZyBpZD0iQ2xhc3NpYy1JbmZyYXN0cnVjdHVyZS1CbGFjay1Db3B5Ij4KICAgICAgICAgICAgICAgIDxnIGlkPSJHcm91cC02IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLjAwMDAwMCwgMC45OTg0MDApIj4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTIuMDAwMDIxMiwyMi45OTgwNDIyIEw3LjczNzAyMTE4LDIyLjk5ODA0MjIgQzQuMTQ2MDIxMTgsMjIuOTk4MDQyMiAwLjg3OTAyMTE4MiwyMC41NzkwNDIyIDAuMTU5MDIxMTgyLDE3LjA2MTA0MjIgQy0wLjcxMjk3ODgxOCwxMi43OTQwNDIyIDIuMTAwMDIxMTgsOC44NTEwNDIyMiA2LjE3ODAyMTE4LDguMTIyMDQyMjIgQzcuMjE2MDIxMTgsMi42OTgwNDIyMiAxMi40NTUwMjEyLC0wLjg1Nzk1Nzc4MyAxNy44NzkwMjEyLDAuMTgwMDQyMjE3IEMyMi41OTEwMjEyLDEuMDgxMDQyMjIgMjUuOTk5MDIxMiw1LjIwMTA0MjIyIDI2LjAwMDAyMTIsOS45OTgwNDIyMiBMMjQuMDAwMDIxMiw5Ljk5ODA0MjIyIEMyNC4wMDEwMjEyLDUuMTAwMDQyMjIgMTkuNTk5MDIxMiwxLjIyOTA0MjIyIDE0LjUzNDAyMTIsMi4xMjgwNDIyMiBDMTAuOTk5MDIxMiwyLjc1NjA0MjIyIDguNDA2MDIxMTgsNS44MjYwNDIyMiA4LjAyMTAyMTE4LDkuMzk2MDQyMjIgTDcuOTU5MDIxMTgsOS45NjEwNDIyMiBMNy4zMTMwMjExOCwxMC4wMDUwNDIyIEM0Ljc0MDAyMTE4LDEwLjE3OTA0MjIgMi40NzcwMjExOCwxMi4wMjIwNDIyIDIuMDcwMDIxMTgsMTQuNTY5MDQyMiBDMS41MTIwMjExOCwxOC4wNTcwNDIyIDQuMTgyMDIxMTgsMjEuMDAzMDQyMiA3LjUwMDAyMTE4LDIwLjk5ODA0MjIgTDEyLjAwMDAyMTIsMjAuOTk4MDQyMiBMMTIuMDAwMDIxMiwyMi45OTgwNDIyIFoiIGlkPSJGaWxsLTQiPjwvcGF0aD4KICAgICAgICAgICAgICAgIDwvZz4KICAgICAgICAgICAgPC9nPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+;", reflect.TypeOf(CloudTreeNode{}): "shape=image;aspect=fixed;image=data:image/svg+xml,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMzNweCIgaGVpZ2h0PSIzMXB4IiB2aWV3Qm94PSIwIDAgMzMgMzEiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUzICg3MjUyMCkgLSBodHRwczovL3NrZXRjaGFwcC5jb20gLS0+CiAgICA8dGl0bGU+SUJNIENsb3VkIEJsYWNrPC90aXRsZT4KICAgIDxkZXNjPkNyZWF0ZWQgd2l0aCBTa2V0Y2guPC9kZXNjPgogICAgPGcgaWQ9IlBhZ2UtMSIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9IklCTS1DbG91ZC1CbGFjayIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMC43ODQ3MjIsIDAuNTAwMTI1KSIgZmlsbD0iIzAwMDAwMCI+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0yNy4xMDIxLDI3LjAxMDYgQzI1Ljg3MDEsMjcuODc5NiAyNC4zNjExLDI4LjI2NzYgMjIuODUzMSwyOC4yNjc2IEw3LjAwNDEsMjguMjY3NiBDNC4xMTIxLDI4LjI3NDYgMS43NjIxLDI1LjkzNDYgMS43NTUxLDIzLjA0MjYgQzEuNzQ5MSwyMC40MTA2IDMuNjk3MSwxOC4xODM2IDYuMzA1MSwxNy44Mzg2IEM2LjQxMTEsMTkuMTYxNiA2Ljc4NzEsMjAuNDQ5NiA3LjQwOTEsMjEuNjIxNiBDNy41OTUxLDIxLjk5MTYgOC4wNDYxLDIyLjE0MDYgOC40MTYxLDIxLjk1NDYgQzguNzg2MSwyMS43Njc2IDguOTM1MSwyMS4zMTc2IDguNzQ4MSwyMC45NDc2IEw4LjczMDEsMjAuOTEyNiBDNy4xMzIxLDE3LjkzNTYgNy40MjkxLDE0LjIxNzYgOS42NzIxLDExLjY4OTYgQzEzLjQ4NjEsNy4zOTI2IDE5Ljc4NzEsOC4wNTI2IDIyLjc1NzEsMTIuMjgxNiBDMjAuMzM0MSwxMi4zNDc2IDE4LjA0NzEsMTMuNDE1NiAxNi40NDExLDE1LjIzMDYgQzE2LjE2MTEsMTUuNTM1NiAxNi4xODExLDE2LjAxMDYgMTYuNDg1MSwxNi4yOTA2IEMxNi43ODkxLDE2LjU3MTYgMTcuMjY0MSwxNi41NTI2IDE3LjU0NTEsMTYuMjQ3NiBMMTcuNTY2MSwxNi4yMjI2IEMxOS41OTUxLDEzLjkyMzYgMjIuODg0MSwxMy4wNTI2IDI1LjcwMzEsMTQuMjYzNiBDMzEuMTY1MSwxNi42MDk2IDMxLjgxMDEsMjMuNjkyNiAyNy4xMDIxLDI3LjAxMDYgTTI0LjU4NTEsMTIuOTE3NiBDMjIuMDU0MSw4LjE3NTYgMTYuMTU5MSw2LjM4MjYgMTEuNDE2MSw4LjkxMzYgQzguNDY1MSwxMC40ODg2IDYuNTI5MSwxMy40Njg2IDYuMjkwMSwxNi44MDY2IEMyLjU4NDEsMTcuMjA0NiAtMC4wOTc5LDIwLjUzMjYgMC4zMDExLDI0LjIzOTYgQzAuNjY5MSwyNy42NjU2IDMuNTU5MSwzMC4yNjM2IDcuMDA0MSwzMC4yNjc2IEwyMy4wMDQxLDMwLjI2NzYgQzI3LjgzNTEsMzAuMjcwNiAzMS43NTMxLDI2LjM1NzYgMzEuNzU2MSwyMS41MjY2IEMzMS43NTkxLDE3LjMwMTYgMjguNzQxMSwxMy42Nzg2IDI0LjU4NTEsMTIuOTE3NiIgaWQ9IkZpbGwtMSI+PC9wYXRoPgogICAgICAgICAgICA8ZyBpZD0iR3JvdXAtNSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMjcuMDAwMDAwLCA4LjI2NzcwMCkiPgogICAgICAgICAgICAgICAgPHBhdGggZD0iTTQuOTAyOCwwLjkxOTcgQzQuNjkzOCwwLjU1NjcgNC4yMjk4LDAuNDMyNyAzLjg2NjgsMC42NDE3IEMzLjg2NjgsMC42NDE3IDMuODY2OCwwLjY0MTcgMy44NjY4LDAuNjQyNyBMMC44NDY4LDIuMzg1NyBDMC40Nzg4LDIuNTg2NyAwLjM0MzgsMy4wNDc3IDAuNTQ0OCwzLjQxNTcgQzAuNzQ1OCwzLjc4MzcgMS4yMDY4LDMuOTE4NyAxLjU3NDgsMy43MTc3IEMxLjU4NDgsMy43MTE3IDEuNTk0OCwzLjcwNTcgMS42MDQ4LDMuNjk5NyBMNC42MjQ4LDEuOTU2NyBDNC45ODc4LDEuNzQ2NyA1LjExMTgsMS4yODI3IDQuOTAyOCwwLjkxOTciIGlkPSJGaWxsLTMiPjwvcGF0aD4KICAgICAgICAgICAgPC9nPgogICAgICAgICAgICA8cGF0aCBkPSJNMjIuNjgxMiw2LjgwMjYgQzIzLjA0MzIsNy4wMTI2IDIzLjUwNzIsNi44ODg2IDIzLjcxNzIsNi41MjU2IEwyMy43MTcyLDYuNTI1NiBMMjUuNDYxMiwzLjUwNTYgQzI1LjY2ODIsMy4xNDA2IDI1LjU0MDIsMi42Nzc2IDI1LjE3NjIsMi40NzA2IEMyNC44MTUyLDIuMjY2NiAyNC4zNTcyLDIuMzg4NiAyNC4xNDcyLDIuNzQ2NiBMMjIuNDAzMiw1Ljc2NjYgQzIyLjE5NDIsNi4xMjk2IDIyLjMxODIsNi41OTM2IDIyLjY4MTIsNi44MDI2IiBpZD0iRmlsbC02Ij48L3BhdGg+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0xNi4wMDQ0LDUuMDE0MSBDMTYuNDIzNCw1LjAxNDEgMTYuNzYzNCw0LjY3NDEgMTcuMzM1NCw0LjI1NTEgTDE3LjMzNTQsMC43NjcxIEMxNi43Njg0LDAuMzQ4MSAxNi40MzI0LDAuMDA1MSAxNi4wMTM0LDAuMDAwMSBDMTUuNTk0NCwtMC4wMDQ5IDE1LjI1MTQsMC4zMzExIDE1LjMzNTQsMC43NTAxIEwxNS4zMzU0LDAuNzY3MSBMMTUuMzM1NCw0LjI1NTEgQzE1LjI0NjQsNC42NzQxIDE1LjU4NTQsNS4wMTQxIDE2LjAwNDQsNS4wMTQxIiBpZD0iRmlsbC04Ij48L3BhdGg+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik04LjI5Miw2LjUyNDggQzguNTA0LDYuODg1OCA4Ljk2OSw3LjAwNjggOS4zMzEsNi43OTQ4IEM5LjY4OCw2LjU4NDggOS44MTEsNi4xMjY4IDkuNjA2LDUuNzY1OCBMNy44NjIsMi43NDU4IEM3LjY1NSwyLjM4MTggNy4xOTIsMi4yNTM4IDYuODI4LDIuNDYwOCBDNi40NjMsMi42Njc4IDYuMzM1LDMuMTMwOCA2LjU0MiwzLjQ5NDggQzYuNTQ0LDMuNDk4OCA2LjU0NiwzLjUwMTggNi41NDgsMy41MDQ4IEw4LjI5Miw2LjUyNDggWiIgaWQ9IkZpbGwtMTAiPjwvcGF0aD4KICAgICAgICAgICAgPGcgaWQ9Ikdyb3VwLTE0IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLjAwMDAwMCwgOC4yNjc3MDApIj4KICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik00LjE2MzEsMi4zODYgTDEuMTQzMSwwLjY0MiBDMC43ODIxLDAuNDMgMC4zMTcxLDAuNTUxIDAuMTA0MSwwLjkxMiBDLTAuMTA3OSwxLjI3MyAwLjAxMzEsMS43MzkgMC4zNzQxLDEuOTUgQzAuMzc4MSwxLjk1MiAwLjM4MTEsMS45NTQgMC4zODQxLDEuOTU2IEwzLjQwNTEsMy43IEMzLjc2NjEsMy45MTIgNC4yMzExLDMuNzkxIDQuNDQzMSwzLjQzIEM0LjY1NTEsMy4wNjkgNC41MzUxLDIuNjA0IDQuMTczMSwyLjM5MiBDNC4xNzAxLDIuMzkgNC4xNjYxLDIuMzg4IDQuMTYzMSwyLjM4NiBaIiBpZD0iRmlsbC0xMiI+PC9wYXRoPgogICAgICAgICAgICA8L2c+CiAgICAgICAgPC9nPgogICAgPC9nPgo8L3N2Zz4=;", @@ -67,7 +60,7 @@ var textStyles = map[reflect.Type]string{ reflect.TypeOf(SubnetTreeNode{}): "text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontFamily=IBM Plex Sans;fontSource=fonts%2FIBMPlexSans-Regular.woff;fontSize=14;", reflect.TypeOf(PartialSGTreeNode{}): "text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontFamily=IBM Plex Sans;fontSource=fonts%2FIBMPlexSans-Regular.woff;fontSize=14;", reflect.TypeOf(ConnectivityTreeNode{}): "edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];", - reflect.TypeOf(VsiLineTreeNode{}): "edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];", + reflect.TypeOf(LogicalLineTreeNode{}): "edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];", } var decoreStyles = map[reflect.Type]string{ @@ -79,29 +72,79 @@ var decoreStyles = map[reflect.Type]string{ reflect.TypeOf(PartialSGTreeNode{}): "rounded=0;whiteSpace=wrap;html=1;strokeColor=none;fillColor=#FA4D56;", } -func (data *drawioData) Style(tn TreeNodeInterface) string { - if reflect.TypeOf(tn).Elem() == reflect.TypeOf(ConnectivityTreeNode{}) { +type drawioStyles struct { + canTypeHaveAMiniIcon map[reflect.Type]bool +} + +func newDrawioStyles(nodes []TreeNodeInterface) drawioStyles { + stl := drawioStyles{} + stl.canTypeHaveAMiniIcon = map[reflect.Type]bool{} + for _, tn := range nodes { + if reflect.TypeOf(tn).Elem() == reflect.TypeOf(VsiTreeNode{}) { + stl.canTypeHaveAMiniIcon[reflect.TypeOf(NITreeNode{})] = true + } + if reflect.TypeOf(tn).Elem() == reflect.TypeOf(VpeTreeNode{}) { + stl.canTypeHaveAMiniIcon[reflect.TypeOf(ResIPTreeNode{})] = true + } + } + return stl +} + +func connectivityStyle(con *ConnectivityTreeNode) string { + startArrow, endArrow := ovalEndEdge, ovalEndEdge + strokeColor := "" + if con.directed { + endArrow = errorEndEdge + } + if con.Src().IsGroupingPoint() && !con.Src().(*GroupPointTreeNode).hasShownSquare() { + startArrow = noneEndEdge + } + if con.Dst().IsGroupingPoint() && !con.Dst().(*GroupPointTreeNode).hasShownSquare() { + endArrow = noneEndEdge + } + if con.router != nil { + strokeColor = connRouteredCollor + } + return fmt.Sprintf(connStyleFormat, endArrow, startArrow, strokeColor) +} + +// mini icons: +// some icons might have mini icons (ni and resIp). the rule is: +// if there are no vsi icon in the canvas, all the ni are displayed as vsi icon, and without mini icons +// if there is a vsi icon in the canvas, than: +// if the ni is connected to a vsi that has only one ni, than the ni displayed as vsi icon, with an ni mini icons +// if the ni is connected to a vsi that has more than one ni, than the ni displayed as ni icon, and without mini icons +// same with resIp and vpe +func (stl *drawioStyles) HasMiniIcon(tn TreeNodeInterface) bool { + if stl.canTypeHaveAMiniIcon[reflect.TypeOf(tn).Elem()] && tn.(IconTreeNodeInterface).hasMiniIcon() { + return true + } + return false +} +func (stl *drawioStyles) Style(tn TreeNodeInterface) string { + tnType := reflect.TypeOf(tn).Elem() + if tnType == reflect.TypeOf(ConnectivityTreeNode{}) { return connectivityStyle(tn.(*ConnectivityTreeNode)) - } else if reflect.TypeOf(tn).Elem() == reflect.TypeOf(NITreeNode{}) && !data.ShowNIIcon { - return styles[reflect.TypeOf(VsiTreeNode{})] + } else if stl.canTypeHaveAMiniIcon[tnType] && !tn.(IconTreeNodeInterface).hasMiniIcon() { + return miniStyles[tnType] } - return styles[reflect.TypeOf(tn).Elem()] + return styles[tnType] +} +func (stl *drawioStyles) MiniIconStyle(tn TreeNodeInterface) string { + return miniStyles[reflect.TypeOf(tn).Elem()] } -func (data *drawioData) TextStyle(tn TreeNodeInterface) string { + +func (stl *drawioStyles) TextStyle(tn TreeNodeInterface) string { return textStyles[reflect.TypeOf(tn).Elem()] } -func (data *drawioData) TagStyle(tn TreeNodeInterface) string { +func (stl *drawioStyles) TagStyle(tn TreeNodeInterface) string { return tagStyles[reflect.TypeOf(tn).Elem()] } -func (data *drawioData) HasTag(tn TreeNodeInterface) bool { +func (stl *drawioStyles) HasTag(tn TreeNodeInterface) bool { _, ok := tagStyles[reflect.TypeOf(tn).Elem()] return ok } -func (data *drawioData) DecoreStyle(tn TreeNodeInterface) string { +func (stl *drawioStyles) DecoreStyle(tn TreeNodeInterface) string { return decoreStyles[reflect.TypeOf(tn).Elem()] } -func (data *drawioData) ElementComment(tn TreeNodeInterface) string { - return reflect.TypeOf(tn).Elem().Name() + " " + tn.Label() -} -func (data *drawioData) FIPStyle() string { return fipStyle } -func (data *drawioData) VsiStyle() string { return vsiStyle } +func (stl *drawioStyles) FIPStyle() string { return fipStyle } diff --git a/pkg/drawio/treeNodeInterface.go b/pkg/drawio/treeNodeInterface.go index c57cb8c92..ce9369182 100644 --- a/pkg/drawio/treeNodeInterface.go +++ b/pkg/drawio/treeNodeInterface.go @@ -24,10 +24,10 @@ package drawio // LineTreeNodeInterface contains TreeNodeInterface, implemented by all line TreeNodes. (connectivity, NI===VSI ) // // abstractTreeNode is the basic struct implementing a TreeNode. -// the structs abstractSquareTreeNode, abstractIconTreeNode, abstractLineTreeNode contains abstractTreeNode -// All structs representing a Square (VpcTreeNode, ZoneTreeNode, SubnetTreeNode...) contains abstractIconTreeNode -// All structs representing an icons (NITreeNode, GatewayTreeNode, UserTreeNode...) contains abstractIconTreeNode -// All structs representing a line (VsiLineTreeNode, ConnectivityTreeNode) contains abstractIconTreeNode +// the structs abstractSquareTreeNode, abstractIconTreeNode, abstractLineTreeNode contain abstractTreeNode +// All structs representing a Square (VpcTreeNode, ZoneTreeNode, SubnetTreeNode...) contain abstractSQuareTreeNode +// All structs representing an icons (NITreeNode, GatewayTreeNode, UserTreeNode...) contain abstractIconTreeNode +// All structs representing a line (LogicalLineTreeNode, ConnectivityTreeNode) contain abstractLineTreeNode // TreeNode main information that a TreeNode holds is: // 1. information about the tree (its parents, its children) diff --git a/pkg/ibmvpc/analysis_output_test.go b/pkg/ibmvpc/analysis_output_test.go index 49891482a..cc1c973b3 100644 --- a/pkg/ibmvpc/analysis_output_test.go +++ b/pkg/ibmvpc/analysis_output_test.go @@ -189,6 +189,12 @@ var tests = []*vpcGeneralTest{ grouping: true, format: vpcmodel.DRAWIO, }, + { + name: "mult_NIs_single_VSI", + useCases: []vpcmodel.OutputUseCase{vpcmodel.AllEndpoints}, + grouping: true, + format: vpcmodel.DRAWIO, + }, //batch3: only vsi-level use-case, no grouping, with debug / md output formats { diff --git a/pkg/ibmvpc/examples/input_mult_NIs_single_VSI.json b/pkg/ibmvpc/examples/input_mult_NIs_single_VSI.json new file mode 100644 index 000000000..bfe071d87 --- /dev/null +++ b/pkg/ibmvpc/examples/input_mult_NIs_single_VSI.json @@ -0,0 +1,1343 @@ +{ + "vpcs": [ + { + "classic_access": false, + "created_at": "2023-04-23T09:16:49.000Z", + "crn": "crn:1", + "cse_source_ips": [ + { + "ip": { + "address": "10.249.193.85" + }, + "zone": { + "href": "href:4", + "name": "us-south-1" + } + }, + { + "ip": { + "address": "10.16.242.44" + }, + "zone": { + "href": "href:5", + "name": "us-south-2" + } + }, + { + "ip": { + "address": "10.249.214.146" + }, + "zone": { + "href": "href:6", + "name": "us-south-3" + } + } + ], + "default_network_acl": { + "crn": "crn:7", + "href": "href:8", + "id": "id:9", + "name": "class-motivate-font-donut" + }, + "default_routing_table": { + "href": "href:10", + "id": "id:11", + "name": "enjoyer-unsure-valley-vigorous", + "resource_type": "routing_table" + }, + "default_security_group": { + "crn": "crn:12", + "href": "href:13", + "id": "id:14", + "name": "throng-avid-undaunted-scheme" + }, + "href": "href:2", + "id": "id:3", + "name": "test-vpc1-ky", + "resource_group": { + "href": "href:15", + "id": "id:16", + "name": "anonymous" + }, + "resource_type": "vpc", + "status": "available", + "tags": [] + } + ], + "subnets": [ + { + "available_ipv4_address_count": 249, + "created_at": "2023-04-23T09:17:31.000Z", + "crn": "crn:17", + "href": "href:18", + "id": "id:19", + "ip_version": "ipv4", + "ipv4_cidr_block": "10.240.10.0/24", + "name": "subnet1-ky", + "network_acl": { + "crn": "crn:20", + "href": "href:21", + "id": "id:22", + "name": "acl1-ky" + }, + "public_gateway": { + "crn": "crn:23", + "href": "href:24", + "id": "id:25", + "name": "public-gw-ky", + "resource_type": "public_gateway" + }, + "resource_group": { + "href": "href:15", + "id": "id:16", + "name": "anonymous" + }, + "resource_type": "subnet", + "routing_table": { + "href": "href:10", + "id": "id:11", + "name": "enjoyer-unsure-valley-vigorous", + "resource_type": "routing_table" + }, + "status": "available", + "total_ipv4_address_count": 256, + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1-ky", + "resource_type": "vpc" + }, + "zone": { + "href": "href:4", + "name": "us-south-1" + }, + "reserved_ips": [ + { + "address": "10.240.10.0", + "auto_delete": false, + "created_at": "2023-04-23T09:17:31.000Z", + "href": "href:26", + "id": "id:27", + "lifecycle_state": "stable", + "name": "ibm-network-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.10.1", + "auto_delete": false, + "created_at": "2023-04-23T09:17:31.000Z", + "href": "href:28", + "id": "id:29", + "lifecycle_state": "stable", + "name": "ibm-default-gateway", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.10.2", + "auto_delete": false, + "created_at": "2023-04-23T09:17:31.000Z", + "href": "href:30", + "id": "id:31", + "lifecycle_state": "stable", + "name": "ibm-dns-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.10.3", + "auto_delete": false, + "created_at": "2023-04-23T09:17:31.000Z", + "href": "href:32", + "id": "id:33", + "lifecycle_state": "stable", + "name": "ibm-reserved-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.10.4", + "auto_delete": true, + "created_at": "2023-04-23T09:17:45.000Z", + "href": "href:34", + "id": "id:35", + "lifecycle_state": "stable", + "name": "swore-griminess-glaucoma-dreadlock", + "owner": "user", + "resource_type": "subnet_reserved_ip", + "target": { + "href": "href:36", + "id": "id:37", + "name": "crispy-value-untold-spoof", + "resource_type": "network_interface" + } + }, + { + "address": "10.240.10.5", + "auto_delete": true, + "created_at": "2023-04-23T09:17:46.000Z", + "href": "href:38", + "id": "id:39", + "lifecycle_state": "stable", + "name": "coeditor-tabby-spindle-railroad", + "owner": "user", + "resource_type": "subnet_reserved_ip", + "target": { + "href": "href:40", + "id": "id:41", + "name": "deposited-dreamboat-correct-mandolin", + "resource_type": "network_interface" + } + }, + { + "address": "10.240.10.255", + "auto_delete": false, + "created_at": "2023-04-23T09:17:31.000Z", + "href": "href:42", + "id": "id:43", + "lifecycle_state": "stable", + "name": "ibm-broadcast-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + } + ], + "tags": [ + "public" + ] + }, + { + "available_ipv4_address_count": 249, + "created_at": "2023-04-23T09:17:15.000Z", + "crn": "crn:44", + "href": "href:45", + "id": "id:46", + "ip_version": "ipv4", + "ipv4_cidr_block": "10.240.20.0/24", + "name": "subnet2-ky", + "network_acl": { + "crn": "crn:20", + "href": "href:21", + "id": "id:22", + "name": "acl1-ky" + }, + "resource_group": { + "href": "href:15", + "id": "id:16", + "name": "anonymous" + }, + "resource_type": "subnet", + "routing_table": { + "href": "href:10", + "id": "id:11", + "name": "enjoyer-unsure-valley-vigorous", + "resource_type": "routing_table" + }, + "status": "available", + "total_ipv4_address_count": 256, + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1-ky", + "resource_type": "vpc" + }, + "zone": { + "href": "href:4", + "name": "us-south-1" + }, + "reserved_ips": [ + { + "address": "10.240.20.0", + "auto_delete": false, + "created_at": "2023-04-23T09:17:15.000Z", + "href": "href:47", + "id": "id:48", + "lifecycle_state": "stable", + "name": "ibm-network-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.20.1", + "auto_delete": false, + "created_at": "2023-04-23T09:17:16.000Z", + "href": "href:49", + "id": "id:50", + "lifecycle_state": "stable", + "name": "ibm-default-gateway", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.20.2", + "auto_delete": false, + "created_at": "2023-04-23T09:17:16.000Z", + "href": "href:51", + "id": "id:52", + "lifecycle_state": "stable", + "name": "ibm-dns-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.20.3", + "auto_delete": false, + "created_at": "2023-04-23T09:17:16.000Z", + "href": "href:53", + "id": "id:54", + "lifecycle_state": "stable", + "name": "ibm-reserved-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + }, + { + "address": "10.240.20.4", + "auto_delete": true, + "created_at": "2023-04-23T09:17:32.000Z", + "href": "href:55", + "id": "id:56", + "lifecycle_state": "stable", + "name": "backroom-yin-undaunted-undertone", + "owner": "user", + "resource_type": "subnet_reserved_ip", + "target": { + "href": "href:57", + "id": "id:58", + "name": "sepia-partner-glorify-italics", + "resource_type": "network_interface" + } + }, + { + "address": "10.240.20.5", + "auto_delete": true, + "created_at": "2023-04-23T09:17:45.000Z", + "href": "href:59", + "id": "id:60", + "lifecycle_state": "stable", + "name": "apt-scary-essence-primp", + "owner": "user", + "resource_type": "subnet_reserved_ip", + "target": { + "href": "href:61", + "id": "id:62", + "name": "eloquence-calamity-bankbook-stylishly", + "resource_type": "network_interface" + } + }, + { + "address": "10.240.20.255", + "auto_delete": false, + "created_at": "2023-04-23T09:17:16.000Z", + "href": "href:63", + "id": "id:64", + "lifecycle_state": "stable", + "name": "ibm-broadcast-address", + "owner": "provider", + "resource_type": "subnet_reserved_ip" + } + ], + "tags": [ + "public" + ] + } + ], + "public_gateways": [ + { + "created_at": "2023-04-23T09:17:09.000Z", + "crn": "crn:23", + "floating_ip": { + "address": "52.118.188.156", + "crn": "crn:65", + "href": "href:66", + "id": "id:67", + "name": "public-gw-ky" + }, + "href": "href:24", + "id": "id:25", + "name": "public-gw-ky", + "resource_group": { + "href": "href:15", + "id": "id:16", + "name": "anonymous" + }, + "resource_type": "public_gateway", + "status": "available", + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1-ky", + "resource_type": "vpc" + }, + "zone": { + "href": "href:4", + "name": "us-south-1" + }, + "tags": [] + } + ], + "floating_ips": [ + { + "address": "52.118.185.133", + "created_at": "2023-04-23T09:18:15.000Z", + "crn": "crn:68", + "href": "href:69", + "id": "id:70", + "name": "floating-ip-ky", + "resource_group": { + "href": "href:15", + "id": "id:16", + "name": "anonymous" + }, + "status": "available", + "target": { + "href": "href:36", + "id": "id:37", + "name": "crispy-value-untold-spoof", + "primary_ip": { + "address": "10.240.10.4", + "href": "href:34", + "id": "id:35", + "name": "swore-griminess-glaucoma-dreadlock", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface" + }, + "zone": { + "href": "href:4", + "name": "us-south-1" + }, + "tags": [] + }, + { + "address": "52.118.188.156", + "created_at": "2023-04-23T09:17:09.000Z", + "crn": "crn:65", + "href": "href:66", + "id": "id:67", + "name": "public-gw-ky", + "resource_group": { + "href": "href:15", + "id": "id:16", + "name": "anonymous" + }, + "status": "available", + "target": { + "href": "href:24", + "id": "id:25", + "name": "public-gw-ky", + "resource_type": "public_gateway", + "crn": "crn:23" + }, + "zone": { + "href": "href:4", + "name": "us-south-1" + }, + "tags": [] + } + ], + "network_acls": [ + { + "created_at": "2023-04-23T09:17:09.000Z", + "crn": "crn:20", + "href": "href:21", + "id": "id:22", + "name": "acl1-ky", + "resource_group": { + "href": "href:15", + "id": "id:16", + "name": "anonymous" + }, + "rules": [ + { + "action": "allow", + "before": { + "href": "href:73", + "id": "id:74", + "name": "inbound" + }, + "created_at": "2023-04-23T09:17:10.000Z", + "destination": "0.0.0.0/0", + "direction": "outbound", + "href": "href:71", + "id": "id:72", + "ip_version": "ipv4", + "name": "outbound", + "source": "0.0.0.0/0", + "protocol": "all" + }, + { + "action": "allow", + "created_at": "2023-04-23T09:17:10.000Z", + "destination": "0.0.0.0/0", + "direction": "inbound", + "href": "href:73", + "id": "id:74", + "ip_version": "ipv4", + "name": "inbound", + "source": "0.0.0.0/0", + "protocol": "all" + } + ], + "subnets": [ + { + "crn": "crn:17", + "href": "href:18", + "id": "id:19", + "name": "subnet1-ky", + "resource_type": "subnet" + }, + { + "crn": "crn:44", + "href": "href:45", + "id": "id:46", + "name": "subnet2-ky", + "resource_type": "subnet" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1-ky", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": "2023-04-23T09:16:49.000Z", + "crn": "crn:7", + "href": "href:8", + "id": "id:9", + "name": "class-motivate-font-donut", + "resource_group": { + "href": "href:15", + "id": "id:16", + "name": "anonymous" + }, + "rules": [ + { + "action": "allow", + "before": { + "href": "href:77", + "id": "id:78", + "name": "allow-outbound" + }, + "created_at": "2023-04-23T09:16:49.000Z", + "destination": "0.0.0.0/0", + "direction": "inbound", + "href": "href:75", + "id": "id:76", + "ip_version": "ipv4", + "name": "allow-inbound", + "source": "0.0.0.0/0", + "protocol": "all" + }, + { + "action": "allow", + "created_at": "2023-04-23T09:16:49.000Z", + "destination": "0.0.0.0/0", + "direction": "outbound", + "href": "href:77", + "id": "id:78", + "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-ky", + "resource_type": "vpc" + }, + "tags": [] + } + ], + "security_groups": [ + { + "created_at": "2023-04-23T09:17:09.000Z", + "crn": "crn:79", + "href": "href:80", + "id": "id:81", + "name": "sg1-ky", + "resource_group": { + "href": "href:15", + "id": "id:16", + "name": "anonymous" + }, + "rules": [ + { + "direction": "outbound", + "href": "href:82", + "id": "id:83", + "ip_version": "ipv4", + "remote": { + "cidr_block": "142.0.0.0/7" + }, + "protocol": "icmp" + }, + { + "direction": "outbound", + "href": "href:84", + "id": "id:85", + "ip_version": "ipv4", + "remote": { + "cidr_block": "161.26.0.0/16" + }, + "port_max": 65535, + "port_min": 1, + "protocol": "udp" + }, + { + "direction": "inbound", + "href": "href:86", + "id": "id:87", + "ip_version": "ipv4", + "remote": { + "crn": "crn:79", + "href": "href:80", + "id": "id:81", + "name": "sg1-ky" + }, + "protocol": "all" + }, + { + "direction": "inbound", + "href": "href:88", + "id": "id:89", + "ip_version": "ipv4", + "remote": { + "crn": "crn:90", + "href": "href:91", + "id": "id:92", + "name": "sg2-ky" + }, + "protocol": "all" + } + ], + "targets": [ + { + "href": "href:36", + "id": "id:37", + "name": "crispy-value-untold-spoof", + "resource_type": "network_interface" + }, + { + "href": "href:40", + "id": "id:41", + "name": "deposited-dreamboat-correct-mandolin", + "resource_type": "network_interface" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1-ky", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": "2023-04-23T09:17:09.000Z", + "crn": "crn:90", + "href": "href:91", + "id": "id:92", + "name": "sg2-ky", + "resource_group": { + "href": "href:15", + "id": "id:16", + "name": "anonymous" + }, + "rules": [ + { + "direction": "outbound", + "href": "href:93", + "id": "id:94", + "ip_version": "ipv4", + "remote": { + "cidr_block": "10.240.30.0/24" + }, + "protocol": "all" + }, + { + "direction": "outbound", + "href": "href:95", + "id": "id:96", + "ip_version": "ipv4", + "remote": { + "cidr_block": "10.240.10.0/24" + }, + "protocol": "all" + }, + { + "direction": "outbound", + "href": "href:97", + "id": "id:98", + "ip_version": "ipv4", + "remote": { + "cidr_block": "142.0.0.0/8" + }, + "protocol": "icmp" + }, + { + "direction": "outbound", + "href": "href:99", + "id": "id:100", + "ip_version": "ipv4", + "remote": { + "cidr_block": "10.240.20.0/24" + }, + "protocol": "all" + }, + { + "direction": "inbound", + "href": "href:101", + "id": "id:102", + "ip_version": "ipv4", + "remote": { + "crn": "crn:90", + "href": "href:91", + "id": "id:92", + "name": "sg2-ky" + }, + "port_max": 65535, + "port_min": 1, + "protocol": "tcp" + }, + { + "direction": "outbound", + "href": "href:103", + "id": "id:104", + "ip_version": "ipv4", + "remote": { + "crn": "crn:90", + "href": "href:91", + "id": "id:92", + "name": "sg2-ky" + }, + "port_max": 65535, + "port_min": 1, + "protocol": "tcp" + }, + { + "direction": "inbound", + "href": "href:105", + "id": "id:106", + "ip_version": "ipv4", + "remote": { + "address": "147.235.219.206" + }, + "port_max": 22, + "port_min": 22, + "protocol": "tcp" + }, + { + "direction": "inbound", + "href": "href:107", + "id": "id:108", + "ip_version": "ipv4", + "remote": { + "crn": "crn:79", + "href": "href:80", + "id": "id:81", + "name": "sg1-ky" + }, + "protocol": "all" + } + ], + "targets": [ + { + "href": "href:57", + "id": "id:58", + "name": "sepia-partner-glorify-italics", + "resource_type": "network_interface" + }, + { + "href": "href:61", + "id": "id:62", + "name": "eloquence-calamity-bankbook-stylishly", + "resource_type": "network_interface" + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1-ky", + "resource_type": "vpc" + }, + "tags": [] + }, + { + "created_at": "2023-04-23T09:16:49.000Z", + "crn": "crn:12", + "href": "href:13", + "id": "id:14", + "name": "throng-avid-undaunted-scheme", + "resource_group": { + "href": "href:15", + "id": "id:16", + "name": "anonymous" + }, + "rules": [ + { + "direction": "outbound", + "href": "href:109", + "id": "id:110", + "ip_version": "ipv4", + "remote": { + "cidr_block": "0.0.0.0/0" + }, + "protocol": "all" + }, + { + "direction": "inbound", + "href": "href:111", + "id": "id:112", + "ip_version": "ipv4", + "remote": { + "crn": "crn:12", + "href": "href:13", + "id": "id:14", + "name": "throng-avid-undaunted-scheme" + }, + "protocol": "all" + } + ], + "targets": [], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1-ky", + "resource_type": "vpc" + }, + "tags": [] + } + ], + "endpoint_gateways": [], + "instances": [ + { + "availability_policy": { + "host_failure": "restart" + }, + "bandwidth": 4000, + "boot_volume_attachment": { + "device": { + "id": "id:118" + }, + "href": "href:116", + "id": "id:117", + "name": "mowing-manorial-lax-spectrum", + "volume": { + "crn": "crn:119", + "href": "href:120", + "id": "id:121", + "name": "enroll-swell-contusion-distill" + } + }, + "created_at": "2023-04-23T09:17:45.000Z", + "crn": "crn:113", + "disks": [], + "href": "href:114", + "id": "id:115", + "image": { + "crn": "crn:122", + "href": "href:123", + "id": "id:124", + "name": "ibm-centos-7-9-minimal-amd64-8" + }, + "lifecycle_reasons": [], + "lifecycle_state": "stable", + "memory": 4, + "metadata_service": { + "enabled": false, + "protocol": "http", + "response_hop_limit": 1 + }, + "name": "vsi3-ky", + "primary_network_interface": { + "href": "href:36", + "id": "id:37", + "name": "crispy-value-untold-spoof", + "primary_ip": { + "address": "10.240.10.4", + "href": "href:34", + "id": "id:35", + "name": "swore-griminess-glaucoma-dreadlock", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "subnet": { + "crn": "crn:17", + "href": "href:18", + "id": "id:19", + "name": "subnet1-ky", + "resource_type": "subnet" + } + }, + "profile": { + "href": "href:125", + "name": "cx2-2x4" + }, + "resource_group": { + "href": "href:15", + "id": "id:16", + "name": "anonymous" + }, + "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:118" + }, + "href": "href:116", + "id": "id:117", + "name": "mowing-manorial-lax-spectrum", + "volume": { + "crn": "crn:119", + "href": "href:120", + "id": "id:121", + "name": "enroll-swell-contusion-distill" + } + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1-ky", + "resource_type": "vpc" + }, + "zone": { + "href": "href:4", + "name": "us-south-1" + }, + "network_interfaces": [ + { + "allow_ip_spoofing": false, + "created_at": "2023-04-23T09:17:45.000Z", + "floating_ips": [ + { + "address": "52.118.185.133", + "crn": "crn:68", + "href": "href:69", + "id": "id:70", + "name": "floating-ip-ky" + } + ], + "href": "href:36", + "id": "id:37", + "name": "crispy-value-untold-spoof", + "port_speed": 1500, + "primary_ip": { + "address": "10.240.10.4", + "href": "href:34", + "id": "id:35", + "name": "swore-griminess-glaucoma-dreadlock", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "security_groups": [ + { + "crn": "crn:79", + "href": "href:80", + "id": "id:81", + "name": "sg1-ky" + } + ], + "status": "available", + "subnet": { + "crn": "crn:17", + "href": "href:18", + "id": "id:19", + "name": "subnet1-ky", + "resource_type": "subnet" + }, + "type": "primary" + }, + { + "allow_ip_spoofing": false, + "created_at": "2023-04-23T09:17:45.000Z", + "floating_ips": [], + "href": "href:61", + "id": "id:62", + "name": "eloquence-calamity-bankbook-stylishly", + "port_speed": 1500, + "primary_ip": { + "address": "10.240.20.5", + "href": "href:59", + "id": "id:60", + "name": "apt-scary-essence-primp", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "security_groups": [ + { + "crn": "crn:90", + "href": "href:91", + "id": "id:92", + "name": "sg2-ky" + } + ], + "status": "available", + "subnet": { + "crn": "crn:44", + "href": "href:45", + "id": "id:46", + "name": "subnet2-ky", + "resource_type": "subnet" + }, + "type": "secondary" + } + ], + "tags": [] + }, + { + "availability_policy": { + "host_failure": "restart" + }, + "bandwidth": 4000, + "boot_volume_attachment": { + "device": { + "id": "id:131" + }, + "href": "href:129", + "id": "id:130", + "name": "atom-mobile-applicant-polo", + "volume": { + "crn": "crn:132", + "href": "href:133", + "id": "id:134", + "name": "headcount-voice-ambition-relax" + } + }, + "created_at": "2023-04-23T09:17:45.000Z", + "crn": "crn:126", + "disks": [], + "href": "href:127", + "id": "id:128", + "image": { + "crn": "crn:122", + "href": "href:123", + "id": "id:124", + "name": "ibm-centos-7-9-minimal-amd64-8" + }, + "lifecycle_reasons": [], + "lifecycle_state": "stable", + "memory": 4, + "metadata_service": { + "enabled": false, + "protocol": "http", + "response_hop_limit": 1 + }, + "name": "vsi1-ky", + "primary_network_interface": { + "href": "href:40", + "id": "id:41", + "name": "deposited-dreamboat-correct-mandolin", + "primary_ip": { + "address": "10.240.10.5", + "href": "href:38", + "id": "id:39", + "name": "coeditor-tabby-spindle-railroad", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "subnet": { + "crn": "crn:17", + "href": "href:18", + "id": "id:19", + "name": "subnet1-ky", + "resource_type": "subnet" + } + }, + "profile": { + "href": "href:125", + "name": "cx2-2x4" + }, + "resource_group": { + "href": "href:15", + "id": "id:16", + "name": "anonymous" + }, + "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:131" + }, + "href": "href:129", + "id": "id:130", + "name": "atom-mobile-applicant-polo", + "volume": { + "crn": "crn:132", + "href": "href:133", + "id": "id:134", + "name": "headcount-voice-ambition-relax" + } + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1-ky", + "resource_type": "vpc" + }, + "zone": { + "href": "href:4", + "name": "us-south-1" + }, + "network_interfaces": [ + { + "allow_ip_spoofing": false, + "created_at": "2023-04-23T09:17:45.000Z", + "floating_ips": [], + "href": "href:40", + "id": "id:41", + "name": "deposited-dreamboat-correct-mandolin", + "port_speed": 3000, + "primary_ip": { + "address": "10.240.10.5", + "href": "href:38", + "id": "id:39", + "name": "coeditor-tabby-spindle-railroad", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "security_groups": [ + { + "crn": "crn:79", + "href": "href:80", + "id": "id:81", + "name": "sg1-ky" + } + ], + "status": "available", + "subnet": { + "crn": "crn:17", + "href": "href:18", + "id": "id:19", + "name": "subnet1-ky", + "resource_type": "subnet" + }, + "type": "primary" + } + ], + "tags": [] + }, + { + "availability_policy": { + "host_failure": "restart" + }, + "bandwidth": 4000, + "boot_volume_attachment": { + "device": { + "id": "id:140" + }, + "href": "href:138", + "id": "id:139", + "name": "matcher-chains-survivor-repossess", + "volume": { + "crn": "crn:141", + "href": "href:142", + "id": "id:143", + "name": "devolve-unpiloted-pension-badland" + } + }, + "created_at": "2023-04-23T09:17:32.000Z", + "crn": "crn:135", + "disks": [], + "href": "href:136", + "id": "id:137", + "image": { + "crn": "crn:122", + "href": "href:123", + "id": "id:124", + "name": "ibm-centos-7-9-minimal-amd64-8" + }, + "lifecycle_reasons": [], + "lifecycle_state": "stable", + "memory": 4, + "metadata_service": { + "enabled": false, + "protocol": "http", + "response_hop_limit": 1 + }, + "name": "vsi2-ky", + "primary_network_interface": { + "href": "href:57", + "id": "id:58", + "name": "sepia-partner-glorify-italics", + "primary_ip": { + "address": "10.240.20.4", + "href": "href:55", + "id": "id:56", + "name": "backroom-yin-undaunted-undertone", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "subnet": { + "crn": "crn:44", + "href": "href:45", + "id": "id:46", + "name": "subnet2-ky", + "resource_type": "subnet" + } + }, + "profile": { + "href": "href:125", + "name": "cx2-2x4" + }, + "resource_group": { + "href": "href:15", + "id": "id:16", + "name": "anonymous" + }, + "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:140" + }, + "href": "href:138", + "id": "id:139", + "name": "matcher-chains-survivor-repossess", + "volume": { + "crn": "crn:141", + "href": "href:142", + "id": "id:143", + "name": "devolve-unpiloted-pension-badland" + } + } + ], + "vpc": { + "crn": "crn:1", + "href": "href:2", + "id": "id:3", + "name": "test-vpc1-ky", + "resource_type": "vpc" + }, + "zone": { + "href": "href:4", + "name": "us-south-1" + }, + "network_interfaces": [ + { + "allow_ip_spoofing": false, + "created_at": "2023-04-23T09:17:32.000Z", + "floating_ips": [], + "href": "href:57", + "id": "id:58", + "name": "sepia-partner-glorify-italics", + "port_speed": 3000, + "primary_ip": { + "address": "10.240.20.4", + "href": "href:55", + "id": "id:56", + "name": "backroom-yin-undaunted-undertone", + "resource_type": "subnet_reserved_ip" + }, + "resource_type": "network_interface", + "security_groups": [ + { + "crn": "crn:90", + "href": "href:91", + "id": "id:92", + "name": "sg2-ky" + } + ], + "status": "available", + "subnet": { + "crn": "crn:44", + "href": "href:45", + "id": "id:46", + "name": "subnet2-ky", + "resource_type": "subnet" + }, + "type": "primary" + } + ], + "tags": [] + } + ], + "routing_tables": [ + { + "accept_routes_from": [ + { + "resource_type": "vpn_gateway" + }, + { + "resource_type": "vpn_server" + } + ], + "created_at": "2023-04-23T09:16:49.000Z", + "href": "href:10", + "id": "id:11", + "is_default": true, + "lifecycle_state": "stable", + "name": "enjoyer-unsure-valley-vigorous", + "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:17", + "href": "href:18", + "id": "id:19", + "name": "subnet1-ky", + "resource_type": "subnet" + }, + { + "crn": "crn:44", + "href": "href:45", + "id": "id:46", + "name": "subnet2-ky", + "resource_type": "subnet" + } + ], + "routes": [] + } + ], + "load_balancers": [] +} \ No newline at end of file diff --git a/pkg/ibmvpc/ibmDrawioGenerator.go b/pkg/ibmvpc/ibmDrawioGenerator.go index 17a7551e7..4c42982c2 100644 --- a/pkg/ibmvpc/ibmDrawioGenerator.go +++ b/pkg/ibmvpc/ibmDrawioGenerator.go @@ -9,15 +9,6 @@ import ( func (v *VPC) GenerateDrawioTreeNode(gen *vpcmodel.DrawioGenerator) drawio.TreeNodeInterface { return drawio.NewVpcTreeNode(gen.Cloud(), v.Name()) } - -func (v *Vpe) GenerateDrawioTreeNode(gen *vpcmodel.DrawioGenerator) drawio.TreeNodeInterface { - return nil -} - -func (r *ReservedIP) GenerateDrawioTreeNode(gen *vpcmodel.DrawioGenerator) drawio.TreeNodeInterface { - return nil -} - func (z *Zone) IsExternal() bool { return false } func (z *Zone) GenerateDrawioTreeNode(gen *vpcmodel.DrawioGenerator) drawio.TreeNodeInterface { return drawio.NewZoneTreeNode(gen.TreeNode(z.VPC()).(*drawio.VpcTreeNode), z.name) @@ -33,12 +24,8 @@ func (s *Subnet) GenerateDrawioTreeNode(gen *vpcmodel.DrawioGenerator) drawio.Tr func (sgl *SecurityGroupLayer) GenerateDrawioTreeNode(gen *vpcmodel.DrawioGenerator) drawio.TreeNodeInterface { tn := drawio.NewSGTreeNode(gen.TreeNode(sgl.VPC()).(*drawio.VpcTreeNode), sgl.Name()) for _, sg := range sgl.sgList { - for _, ni := range sg.members { - // todo - remove this if after supporting vpe: - if gen.TreeNode(ni) == nil { - continue - } - gen.TreeNode(ni).(*drawio.NITreeNode).SetSG(tn) + for _, member := range sg.members { + tn.AddIcon(gen.TreeNode(member).(drawio.IconTreeNodeInterface)) } } return tn @@ -55,23 +42,25 @@ func (nl *NaclLayer) GenerateDrawioTreeNode(gen *vpcmodel.DrawioGenerator) drawi func (ni *NetworkInterface) GenerateDrawioTreeNode(gen *vpcmodel.DrawioGenerator) drawio.TreeNodeInterface { return drawio.NewNITreeNode( - gen.TreeNode(ni.subnet).(drawio.SquareTreeNodeInterface), - nil, ni.Name()) + gen.TreeNode(ni.subnet).(drawio.SquareTreeNodeInterface), ni.Name()) } func (n *IKSNode) GenerateDrawioTreeNode(gen *vpcmodel.DrawioGenerator) drawio.TreeNodeInterface { return drawio.NewNITreeNode( - gen.TreeNode(n.subnet).(drawio.SquareTreeNodeInterface), - nil, n.Name()) + gen.TreeNode(n.subnet).(drawio.SquareTreeNodeInterface), n.Name()) +} +func (r *ReservedIP) GenerateDrawioTreeNode(gen *vpcmodel.DrawioGenerator) drawio.TreeNodeInterface { + return drawio.NewResIPTreeNode( + gen.TreeNode(r.subnet).(drawio.SquareTreeNodeInterface), r.Name()) } func (v *Vsi) GenerateDrawioTreeNode(gen *vpcmodel.DrawioGenerator) drawio.TreeNodeInterface { if len(v.Nodes()) == 0 { return nil } - vsiNIs := []drawio.TreeNodeInterface{} - for _, ni := range v.Nodes() { - vsiNIs = append(vsiNIs, gen.TreeNode(ni)) + vsiNIs := make([]drawio.TreeNodeInterface, len(v.Nodes())) + for i, ni := range v.Nodes() { + vsiNIs[i] = gen.TreeNode(ni) } // todo - how to handle this error: zone, _ := v.Zone() @@ -80,6 +69,19 @@ func (v *Vsi) GenerateDrawioTreeNode(gen *vpcmodel.DrawioGenerator) drawio.TreeN return nil } +func (v *Vpe) GenerateDrawioTreeNode(gen *vpcmodel.DrawioGenerator) drawio.TreeNodeInterface { + if len(v.Nodes()) == 0 { + return nil + } + resIPs := make([]drawio.TreeNodeInterface, len(v.Nodes())) + for i, resIP := range v.Nodes() { + resIPs[i] = gen.TreeNode(resIP) + } + vpcTn := gen.TreeNode(v.vpc).(drawio.SquareTreeNodeInterface) + drawio.GroupResIPsWithVpe(vpcTn, v.Name(), resIPs) + return nil +} + func (pgw *PublicGateway) GenerateDrawioTreeNode(gen *vpcmodel.DrawioGenerator) drawio.TreeNodeInterface { // todo - how to handle this error: zone, _ := pgw.Zone() diff --git a/pkg/vpcmodel/drawioGenerator.go b/pkg/vpcmodel/drawioGenerator.go index d4f77c366..d6e628908 100644 --- a/pkg/vpcmodel/drawioGenerator.go +++ b/pkg/vpcmodel/drawioGenerator.go @@ -57,18 +57,12 @@ func (exn *ExternalNetwork) GenerateDrawioTreeNode(gen *DrawioGenerator) drawio. } func (g *groupedEndpointsElems) GenerateDrawioTreeNode(gen *DrawioGenerator) drawio.TreeNodeInterface { - // todo - fix with supporting vpe - groupedIconsTNs := []drawio.IconTreeNodeInterface{} - for _, ni := range *g { - if gen.TreeNode(ni) != nil { - groupedIconsTNs = append(groupedIconsTNs, gen.TreeNode(ni).(drawio.IconTreeNodeInterface)) - } - } - if len(groupedIconsTNs) == 0 { - return nil + if len(*g) == 1 { + return gen.TreeNode((*g)[0]) } - if len(groupedIconsTNs) == 1 { - return groupedIconsTNs[0] + groupedIconsTNs := make([]drawio.IconTreeNodeInterface, len(*g)) + for i, node := range *g { + groupedIconsTNs[i] = gen.TreeNode(node).(drawio.IconTreeNodeInterface) } subnetTn := groupedIconsTNs[0].Parent().(*drawio.SubnetTreeNode) return drawio.NewGroupSquareTreeNode(subnetTn, groupedIconsTNs) @@ -94,9 +88,5 @@ func (g *groupedExternalNodes) GenerateDrawioTreeNode(gen *DrawioGenerator) draw func (e *edgeInfo) GenerateDrawioTreeNode(gen *DrawioGenerator) drawio.TreeNodeInterface { srcTn := gen.TreeNode(e.src) dstTn := gen.TreeNode(e.dst) - // todo - remove this when supporting vpe - if srcTn == nil || dstTn == nil { - return nil - } return drawio.NewConnectivityLineTreeNode(gen.Network(), srcTn, dstTn, e.directed, e.label) } diff --git a/pkg/vpcmodel/drawioOutput.go b/pkg/vpcmodel/drawioOutput.go index 28d29fa78..46c4b2732 100644 --- a/pkg/vpcmodel/drawioOutput.go +++ b/pkg/vpcmodel/drawioOutput.go @@ -107,10 +107,6 @@ func (d *DrawioOutputFormatter) createEdges() { } for e, directed := range isEdgeDirected { ei := &edgeInfo{e.src, e.dst, e.label, directed} - // todo - remove if when supporting vpe: - if d.gen.TreeNode(ei) == nil { - continue - } cn := d.gen.TreeNode(ei).(*drawio.ConnectivityTreeNode) if d.routers[cn.Src()] != nil && e.dst.IsExternal() { cn.SetRouter(d.routers[cn.Src()], false)