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)