network_drawer 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +13 -7
- data/examples/simple.json +35 -17
- data/examples/simple.svg +49 -49
- data/examples/simple.yml +77 -0
- data/examples/simple_style.json +1 -0
- data/lib/network_drawer.rb +4 -1
- data/lib/network_drawer/cli.rb +2 -1
- data/lib/network_drawer/diagram.rb +71 -96
- data/lib/network_drawer/element/connection.rb +22 -0
- data/lib/network_drawer/element/element.rb +43 -0
- data/lib/network_drawer/element/layer.rb +48 -0
- data/lib/network_drawer/element/node.rb +39 -0
- data/lib/network_drawer/source.rb +36 -2
- data/lib/network_drawer/version.rb +1 -1
- metadata +7 -4
- data/examples/simple.dot +0 -53
- data/lib/network_drawer/style.rb +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8e3fd2565dcf2fc91d794f85263bfb54214f6730
|
4
|
+
data.tar.gz: 1f7503b24294cec4c9bf6d34cae092d4a2efcb2d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5a79d2f85c393a680bc50ee2552f81cffed56741570cd6adc3a81dc0058a76bb480f7316194f1aeeb2286e6f0c352c5235b9521e750b04549ceacdf2a94b4723
|
7
|
+
data.tar.gz: eef66c5545b072c38df3e58d9f61822510febc96063022b9cb87dbb5bac75b88e7f56d766172930ab5c73c8c0819cdc4b6511b7ac4362e9bf45c467f9ecba1af
|
data/README.md
CHANGED
@@ -1,18 +1,20 @@
|
|
1
1
|
# NetworkDrawer
|
2
2
|
|
3
|
-
A network diagram drawer with json.
|
3
|
+
A network diagram drawer with json or yaml.
|
4
|
+
|
5
|
+
[](http://badge.fury.io/rb/network_drawer)
|
4
6
|
|
5
7
|
## Installation
|
6
8
|
|
7
|
-
Ensure you can use [Graphviz](http://www.graphviz.org/), before installing network_drawer
|
9
|
+
Ensure you can use [Graphviz](http://www.graphviz.org/), before installing network_drawer.
|
8
10
|
|
9
|
-
You can install Graphviz as follow
|
11
|
+
You can install Graphviz as follow.
|
10
12
|
```
|
11
13
|
# Mac OS X with brew
|
12
14
|
brew install graphviz
|
13
15
|
|
14
16
|
# CentOS
|
15
|
-
yum
|
17
|
+
yum install graphviz
|
16
18
|
|
17
19
|
# Ubuntu
|
18
20
|
apt-get install graphviz
|
@@ -34,15 +36,19 @@ Or install it yourself as:
|
|
34
36
|
|
35
37
|
## Usage
|
36
38
|
|
37
|
-
You can draw a network diagram:
|
39
|
+
You can draw a network diagram with a JSON or YAML file with SVG format:
|
38
40
|
|
39
41
|
$ bundle exec network_drawer draw examples/simple.json
|
40
42
|
|
41
|
-
|
43
|
+
$ bundle exec network_drawer draw examples/simple.yml
|
44
|
+
|
45
|
+
You can draw a network diagram with specified style:
|
42
46
|
|
43
47
|
$ bundle exec network_drawer draw examples/simple.json -s examples/simple_style.json
|
44
48
|
|
45
|
-
|
49
|
+
$ bundle exec network_drawer draw examples/simple.yml -s examples/simple_style.yml
|
50
|
+
|
51
|
+
You can draw a network diagram with png format:
|
46
52
|
|
47
53
|
$ bundle exec network_drawer draw examples/simple.json -f png
|
48
54
|
|
data/examples/simple.json
CHANGED
@@ -1,26 +1,44 @@
|
|
1
1
|
{
|
2
|
-
"layers":
|
3
|
-
|
4
|
-
"
|
2
|
+
"layers": [
|
3
|
+
{
|
4
|
+
"Web": {
|
5
|
+
"nodes": [
|
6
|
+
{
|
7
|
+
"WebLB": {
|
8
|
+
"ports": ["80/tcp", "443/tcp"],
|
9
|
+
"type": "LB",
|
10
|
+
"url": "https://github.com/otahi/network_drawer/"
|
11
|
+
}
|
12
|
+
},
|
13
|
+
{ "Web001": { "ports": ["80/tcp"] } },
|
14
|
+
{ "Web002": { "ports": ["80/tcp"] } }
|
15
|
+
]
|
16
|
+
},
|
17
|
+
"layers": [
|
5
18
|
{
|
6
|
-
"
|
7
|
-
"
|
8
|
-
|
9
|
-
|
19
|
+
"Image": {
|
20
|
+
"nodes": {
|
21
|
+
"ImageWeb001": {
|
22
|
+
"ports": ["80/tcp"]
|
23
|
+
},
|
24
|
+
"ImageWeb002": {
|
25
|
+
"ports": ["80/tcp"]
|
26
|
+
}
|
27
|
+
}
|
10
28
|
}
|
11
|
-
}
|
12
|
-
{ "Web001": { "ports": ["80/tcp"] } },
|
13
|
-
{ "Web002": { "ports": ["80/tcp"] } }
|
29
|
+
}
|
14
30
|
]
|
15
31
|
},
|
16
|
-
|
17
|
-
"
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
32
|
+
{
|
33
|
+
"App": {
|
34
|
+
"nodes": [
|
35
|
+
{ "AppLB": { "ports": ["80/tcp", "25/tcp"], "type": "LB" } },
|
36
|
+
{ "App001": { "ports": ["80/tcp", "25/tcp"] } },
|
37
|
+
{ "App002": { "ports": ["80/tcp", "25/tcp"] } }
|
38
|
+
]
|
39
|
+
}
|
22
40
|
}
|
23
|
-
|
41
|
+
],
|
24
42
|
"nodes": [
|
25
43
|
{ "Browser": {}, "type": "Client" },
|
26
44
|
{ "Mail Server": {}, "type": "Client" }
|
data/examples/simple.svg
CHANGED
@@ -6,20 +6,20 @@
|
|
6
6
|
<!-- Title: simple Pages: 1 -->
|
7
7
|
<svg width="336pt" height="460pt"
|
8
8
|
viewBox="0.00 0.00 336.00 460.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
9
|
-
<g id="
|
9
|
+
<g id="0" class="graph" transform="scale(1 1) rotate(0) translate(4 456)">
|
10
10
|
<title>simple</title>
|
11
11
|
<polygon fill="white" stroke="white" points="-4,4 -4,-456 332,-456 332,4 -4,4"/>
|
12
|
-
<g id="
|
12
|
+
<g id="1" class="cluster"><title>cluster_Web</title>
|
13
13
|
<polygon fill="none" stroke="black" points="105,-212 105,-408 295,-408 295,-212 105,-212"/>
|
14
14
|
<text text-anchor="middle" x="200" y="-390" font-family="Helvetica,sans-Serif" font-size="14.00">Web</text>
|
15
15
|
</g>
|
16
|
-
<g id="
|
16
|
+
<g id="2" class="cluster"><title>cluster_App</title>
|
17
17
|
<polygon fill="none" stroke="black" points="63,-8 63,-204 320,-204 320,-8 63,-8"/>
|
18
18
|
<text text-anchor="middle" x="191.5" y="-186" font-family="Helvetica,sans-Serif" font-size="14.00">App</text>
|
19
19
|
</g>
|
20
|
-
<!--
|
21
|
-
<g id="
|
22
|
-
<g id="
|
20
|
+
<!-- 0 -->
|
21
|
+
<g id="0" class="node"><title>0</title>
|
22
|
+
<g id="a_0"><a xlink:href="https://github.com/otahi/network_drawer/" xlink:title="WebLB">
|
23
23
|
<path fill="azure" stroke="black" stroke-dasharray="1,5" d="M247,-375.5C247,-375.5 153,-375.5 153,-375.5 147,-375.5 141,-369.5 141,-363.5 141,-363.5 141,-328.5 141,-328.5 141,-322.5 147,-316.5 153,-316.5 153,-316.5 247,-316.5 247,-316.5 253,-316.5 259,-322.5 259,-328.5 259,-328.5 259,-363.5 259,-363.5 259,-369.5 253,-375.5 247,-375.5"/>
|
24
24
|
<polygon fill="none" stroke="black" points="151,-346 151,-369 196,-369 196,-346 151,-346"/>
|
25
25
|
<text text-anchor="start" x="154.431" y="-351.9" font-family="Helvetica,sans-Serif" font-size="14.00">80/tcp</text>
|
@@ -30,9 +30,9 @@
|
|
30
30
|
</a>
|
31
31
|
</g>
|
32
32
|
</g>
|
33
|
-
<!--
|
34
|
-
<g id="
|
35
|
-
<g id="
|
33
|
+
<!-- 1 -->
|
34
|
+
<g id="1" class="node"><title>1</title>
|
35
|
+
<g id="a_1"><a xlink:title="Web001">
|
36
36
|
<polygon fill="none" stroke="black" points="191,-279.5 113,-279.5 113,-220.5 191,-220.5 191,-279.5"/>
|
37
37
|
<polygon fill="none" stroke="black" points="123,-250 123,-273 181,-273 181,-250 123,-250"/>
|
38
38
|
<text text-anchor="start" x="132.931" y="-255.9" font-family="Helvetica,sans-Serif" font-size="14.00">80/tcp</text>
|
@@ -41,14 +41,14 @@
|
|
41
41
|
</a>
|
42
42
|
</g>
|
43
43
|
</g>
|
44
|
-
<!--
|
45
|
-
<g id="
|
44
|
+
<!-- 0->1 -->
|
45
|
+
<g id="3" class="edge"><title>0->1:p80tcp</title>
|
46
46
|
<path fill="none" stroke="blue" d="M199.141,-316.436C198.045,-299.18 195.572,-278.608 190.026,-268.401"/>
|
47
47
|
<polygon fill="blue" stroke="blue" points="192,-265.499 182,-262 187.636,-270.972 192,-265.499"/>
|
48
48
|
</g>
|
49
|
-
<!--
|
50
|
-
<g id="
|
51
|
-
<g id="
|
49
|
+
<!-- 2 -->
|
50
|
+
<g id="2" class="node"><title>2</title>
|
51
|
+
<g id="a_2"><a xlink:title="Web002">
|
52
52
|
<polygon fill="none" stroke="black" points="287,-279.5 209,-279.5 209,-220.5 287,-220.5 287,-279.5"/>
|
53
53
|
<polygon fill="none" stroke="black" points="219,-250 219,-273 277,-273 277,-250 219,-250"/>
|
54
54
|
<text text-anchor="start" x="228.931" y="-255.9" font-family="Helvetica,sans-Serif" font-size="14.00">80/tcp</text>
|
@@ -57,14 +57,14 @@
|
|
57
57
|
</a>
|
58
58
|
</g>
|
59
59
|
</g>
|
60
|
-
<!--
|
61
|
-
<g id="
|
60
|
+
<!-- 0->2 -->
|
61
|
+
<g id="4" class="edge"><title>0->2:p80tcp</title>
|
62
62
|
<path fill="none" stroke="blue" d="M200.859,-316.436C201.955,-299.18 204.428,-278.608 209.974,-268.401"/>
|
63
63
|
<polygon fill="blue" stroke="blue" points="212.364,-270.972 218,-262 208,-265.499 212.364,-270.972"/>
|
64
64
|
</g>
|
65
|
-
<!--
|
66
|
-
<g id="
|
67
|
-
<g id="
|
65
|
+
<!-- 3 -->
|
66
|
+
<g id="3" class="node"><title>3</title>
|
67
|
+
<g id="a_3"><a xlink:title="AppLB">
|
68
68
|
<path fill="azure" stroke="black" stroke-dasharray="1,5" d="M218.25,-171.5C218.25,-171.5 131.75,-171.5 131.75,-171.5 125.75,-171.5 119.75,-165.5 119.75,-159.5 119.75,-159.5 119.75,-124.5 119.75,-124.5 119.75,-118.5 125.75,-112.5 131.75,-112.5 131.75,-112.5 218.25,-112.5 218.25,-112.5 224.25,-112.5 230.25,-118.5 230.25,-124.5 230.25,-124.5 230.25,-159.5 230.25,-159.5 230.25,-165.5 224.25,-171.5 218.25,-171.5"/>
|
69
69
|
<polygon fill="none" stroke="black" points="130,-142 130,-165 175,-165 175,-142 130,-142"/>
|
70
70
|
<text text-anchor="start" x="133.431" y="-147.9" font-family="Helvetica,sans-Serif" font-size="14.00">80/tcp</text>
|
@@ -75,19 +75,19 @@
|
|
75
75
|
</a>
|
76
76
|
</g>
|
77
77
|
</g>
|
78
|
-
<!--
|
79
|
-
<g id="
|
78
|
+
<!-- 1->3 -->
|
79
|
+
<g id="5" class="edge"><title>1->3:p80tcp</title>
|
80
80
|
<path fill="none" stroke="blue" d="M152,-220.191C152,-207.217 152,-191.442 152,-176.321"/>
|
81
81
|
<polygon fill="blue" stroke="blue" points="155.5,-176 152,-166 148.5,-176 155.5,-176"/>
|
82
82
|
</g>
|
83
|
-
<!--
|
84
|
-
<g id="
|
83
|
+
<!-- 2->3 -->
|
84
|
+
<g id="6" class="edge"><title>2->3:p80tcp</title>
|
85
85
|
<path fill="none" stroke="blue" d="M212.526,-220.441C192.443,-204.036 169.215,-184.601 158.292,-173.792"/>
|
86
86
|
<polygon fill="blue" stroke="blue" points="161.006,-171.581 152,-166 155.559,-175.979 161.006,-171.581"/>
|
87
87
|
</g>
|
88
|
-
<!--
|
89
|
-
<g id="
|
90
|
-
<g id="
|
88
|
+
<!-- 4 -->
|
89
|
+
<g id="4" class="node"><title>4</title>
|
90
|
+
<g id="a_4"><a xlink:title="App001">
|
91
91
|
<polygon fill="none" stroke="black" points="182.25,-75.5 71.75,-75.5 71.75,-16.5 182.25,-16.5 182.25,-75.5"/>
|
92
92
|
<polygon fill="none" stroke="black" points="82,-46 82,-69 127,-69 127,-46 82,-46"/>
|
93
93
|
<text text-anchor="start" x="85.4312" y="-51.9" font-family="Helvetica,sans-Serif" font-size="14.00">80/tcp</text>
|
@@ -98,19 +98,19 @@
|
|
98
98
|
</a>
|
99
99
|
</g>
|
100
100
|
</g>
|
101
|
-
<!--
|
102
|
-
<g id="
|
101
|
+
<!-- 3->4 -->
|
102
|
+
<g id="7" class="edge"><title>3->4:p25tcp</title>
|
103
103
|
<path fill="none" stroke="green" d="M160.623,-112.37C156.71,-102.677 153.148,-91.4558 151.693,-80.2467"/>
|
104
104
|
<polygon fill="green" stroke="green" points="155.167,-79.7409 151,-70 148.183,-80.2135 155.167,-79.7409"/>
|
105
105
|
</g>
|
106
|
-
<!--
|
107
|
-
<g id="
|
106
|
+
<!-- 3->4 -->
|
107
|
+
<g id="8" class="edge"><title>3->4:p80tcp</title>
|
108
108
|
<path fill="none" stroke="blue" d="M126.856,-112.424C116.765,-103.478 108.243,-92.5876 105.197,-79.976"/>
|
109
109
|
<polygon fill="blue" stroke="blue" points="108.667,-79.5118 104,-70 101.716,-80.3458 108.667,-79.5118"/>
|
110
110
|
</g>
|
111
|
-
<!--
|
112
|
-
<g id="
|
113
|
-
<g id="
|
111
|
+
<!-- 5 -->
|
112
|
+
<g id="5" class="node"><title>5</title>
|
113
|
+
<g id="a_5"><a xlink:title="App002">
|
114
114
|
<polygon fill="none" stroke="black" points="311.25,-75.5 200.75,-75.5 200.75,-16.5 311.25,-16.5 311.25,-75.5"/>
|
115
115
|
<polygon fill="none" stroke="black" points="211,-46 211,-69 256,-69 256,-46 211,-46"/>
|
116
116
|
<text text-anchor="start" x="214.431" y="-51.9" font-family="Helvetica,sans-Serif" font-size="14.00">80/tcp</text>
|
@@ -121,44 +121,44 @@
|
|
121
121
|
</a>
|
122
122
|
</g>
|
123
123
|
</g>
|
124
|
-
<!--
|
125
|
-
<g id="
|
124
|
+
<!-- 3->5 -->
|
125
|
+
<g id="9" class="edge"><title>3->5:p25tcp</title>
|
126
126
|
<path fill="none" stroke="green" d="M230.267,-125.47C252.302,-116.05 273.686,-101.572 278.832,-80.0328"/>
|
127
127
|
<polygon fill="green" stroke="green" points="282.32,-80.3376 280,-70 275.367,-79.5283 282.32,-80.3376"/>
|
128
128
|
</g>
|
129
|
-
<!--
|
130
|
-
<g id="
|
129
|
+
<!-- 3->5 -->
|
130
|
+
<g id="10" class="edge"><title>3->5:p80tcp</title>
|
131
131
|
<path fill="none" stroke="blue" d="M181.385,-112.436C186.051,-94.4294 192.996,-72.8124 201.291,-63.1294"/>
|
132
132
|
<polygon fill="blue" stroke="blue" points="203.16,-66.0907 210,-58 199.607,-60.059 203.16,-66.0907"/>
|
133
133
|
</g>
|
134
|
-
<!--
|
135
|
-
<g id="
|
136
|
-
<g id="
|
134
|
+
<!-- 6 -->
|
135
|
+
<g id="6" class="node"><title>6</title>
|
136
|
+
<g id="a_6"><a xlink:title="Browser">
|
137
137
|
<polygon fill="none" stroke="black" points="237,-452 161,-452 161,-416 237,-416 237,-452"/>
|
138
138
|
<text text-anchor="start" x="173.328" y="-427.9" font-family="Helvetica,sans-Serif" font-size="14.00">Browser</text>
|
139
139
|
</a>
|
140
140
|
</g>
|
141
141
|
</g>
|
142
|
-
<!--
|
143
|
-
<g id="
|
142
|
+
<!-- 6->0 -->
|
143
|
+
<g id="0" class="edge"><title>6->0:p80tcp</title>
|
144
144
|
<path fill="none" stroke="blue" d="M187.672,-415.857C182.088,-406.095 176.087,-393.216 173.879,-380.063"/>
|
145
145
|
<polygon fill="blue" stroke="blue" points="177.357,-379.657 173,-370 170.384,-380.267 177.357,-379.657"/>
|
146
146
|
</g>
|
147
|
-
<!--
|
148
|
-
<g id="
|
147
|
+
<!-- 6->0 -->
|
148
|
+
<g id="1" class="edge"><title>6->0:p443tcp</title>
|
149
149
|
<path fill="none" stroke="black" d="M209.893,-415.8C215.261,-406.018 221.032,-393.129 223.155,-380.02"/>
|
150
150
|
<polygon fill="black" stroke="black" points="226.647,-380.259 224,-370 219.672,-379.67 226.647,-380.259"/>
|
151
151
|
</g>
|
152
|
-
<!--
|
153
|
-
<g id="
|
154
|
-
<g id="
|
152
|
+
<!-- 7 -->
|
153
|
+
<g id="7" class="node"><title>7</title>
|
154
|
+
<g id="a_7"><a xlink:title="Mail Server">
|
155
155
|
<polygon fill="none" stroke="black" points="94.25,-268 -0.25,-268 -0.25,-232 94.25,-232 94.25,-268"/>
|
156
156
|
<text text-anchor="start" x="12.1035" y="-243.9" font-family="Helvetica,sans-Serif" font-size="14.00">Mail Server</text>
|
157
157
|
</a>
|
158
158
|
</g>
|
159
159
|
</g>
|
160
|
-
<!--
|
161
|
-
<g id="
|
160
|
+
<!-- 7->3 -->
|
161
|
+
<g id="2" class="edge"><title>7->3:p25tcp</title>
|
162
162
|
<path fill="none" stroke="green" d="M70.1237,-231.94C79.4894,-225.355 90.5446,-217.983 101,-212 139.498,-189.969 190.301,-210.355 198.004,-175.979"/>
|
163
163
|
<polygon fill="green" stroke="green" points="201.489,-176.298 199,-166 194.524,-175.603 201.489,-176.298"/>
|
164
164
|
</g>
|
data/examples/simple.yml
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
layers:
|
2
|
+
- Web:
|
3
|
+
nodes:
|
4
|
+
- WebLB:
|
5
|
+
ports:
|
6
|
+
- 80/tcp
|
7
|
+
- 443/tcp
|
8
|
+
type: LB
|
9
|
+
url: https://github.com/otahi/network_drawer/
|
10
|
+
- Web001:
|
11
|
+
ports:
|
12
|
+
- 80/tcp
|
13
|
+
- Web002:
|
14
|
+
ports:
|
15
|
+
- 80/tcp
|
16
|
+
layers:
|
17
|
+
- Image:
|
18
|
+
nodes:
|
19
|
+
ImageWeb001:
|
20
|
+
ports:
|
21
|
+
- 80/tcp
|
22
|
+
ImageWeb002:
|
23
|
+
ports:
|
24
|
+
- 80/tcp
|
25
|
+
- App:
|
26
|
+
nodes:
|
27
|
+
- AppLB:
|
28
|
+
ports:
|
29
|
+
- 80/tcp
|
30
|
+
- 25/tcp
|
31
|
+
type: LB
|
32
|
+
- App001:
|
33
|
+
ports:
|
34
|
+
- 80/tcp
|
35
|
+
- 25/tcp
|
36
|
+
- App002:
|
37
|
+
ports:
|
38
|
+
- 80/tcp
|
39
|
+
- 25/tcp
|
40
|
+
nodes:
|
41
|
+
- Browser:
|
42
|
+
type: Client
|
43
|
+
- Mail Server:
|
44
|
+
type: Client
|
45
|
+
connections:
|
46
|
+
- from: Browser
|
47
|
+
to: WebLB:80/tcp
|
48
|
+
type: HTTP
|
49
|
+
- from: Browser
|
50
|
+
to: WebLB:443/tcp
|
51
|
+
- from: Mail Server
|
52
|
+
to: AppLB:25/tcp
|
53
|
+
type: SMTP
|
54
|
+
- from: WebLB
|
55
|
+
to: Web001:80/tcp
|
56
|
+
type: HTTP
|
57
|
+
- from: WebLB
|
58
|
+
to: Web002:80/tcp
|
59
|
+
type: HTTP
|
60
|
+
- from: Web001
|
61
|
+
to: AppLB:80/tcp
|
62
|
+
type: HTTP
|
63
|
+
- from: Web002
|
64
|
+
to: AppLB:80/tcp
|
65
|
+
type: HTTP
|
66
|
+
- from: AppLB
|
67
|
+
to: App001:25/tcp
|
68
|
+
type: SMTP
|
69
|
+
- from: AppLB
|
70
|
+
to: App001:80/tcp
|
71
|
+
type: HTTP
|
72
|
+
- from: AppLB
|
73
|
+
to: App002:25/tcp
|
74
|
+
type: SMTP
|
75
|
+
- from: AppLB
|
76
|
+
to: App002:80/tcp
|
77
|
+
type: HTTP
|
data/examples/simple_style.json
CHANGED
data/lib/network_drawer.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
require 'network_drawer/version'
|
2
2
|
require 'network_drawer/cli'
|
3
|
+
require 'network_drawer/element/element'
|
4
|
+
require 'network_drawer/element/layer'
|
5
|
+
require 'network_drawer/element/node'
|
6
|
+
require 'network_drawer/element/connection'
|
3
7
|
require 'network_drawer/diagram'
|
4
8
|
require 'network_drawer/source'
|
5
|
-
require 'network_drawer/style'
|
data/lib/network_drawer/cli.rb
CHANGED
@@ -12,7 +12,8 @@ module NetworkDrawer
|
|
12
12
|
default: :svg)
|
13
13
|
def draw(source_file)
|
14
14
|
src = Source.read(source_file)
|
15
|
-
op = {
|
15
|
+
op = {}
|
16
|
+
op = { style: Source.read(options[:style]) } if options[:style]
|
16
17
|
op.merge!(format: options[:format])
|
17
18
|
dest_file = source_file.gsub(File.extname(source_file), '')
|
18
19
|
Diagram.draw(src, dest_file, op)
|
@@ -5,13 +5,10 @@ module NetworkDrawer
|
|
5
5
|
class Diagram
|
6
6
|
TOP_LAYER = :networkdrawertop
|
7
7
|
DEFAULT_OPTIONS = {}
|
8
|
-
DEFAULT_STYLE = { fontname: 'Helvetica' }
|
9
|
-
DEFAULT_NODE_STYLE = { fontname: 'Helvetica', shape: 'box' }
|
10
|
-
DEFAULT_LINE_STYLE = {}
|
11
8
|
|
12
9
|
def self.draw(source, dest_file, options = {})
|
13
|
-
|
14
|
-
|
10
|
+
diagram = new(source, dest_file, options)
|
11
|
+
diagram.draw
|
15
12
|
end
|
16
13
|
|
17
14
|
def initialize(source, dest_file, options = {})
|
@@ -22,123 +19,101 @@ module NetworkDrawer
|
|
22
19
|
File.basename(@dest_file, '.*')
|
23
20
|
@nodes = {}
|
24
21
|
@layers = {}
|
22
|
+
@connections = []
|
25
23
|
@style = options[:style]
|
26
24
|
@gv = Gviz.new(@title)
|
27
25
|
end
|
28
26
|
|
29
27
|
def draw
|
30
|
-
@
|
31
|
-
@
|
32
|
-
|
33
|
-
create_connections
|
28
|
+
@layers = create_layers
|
29
|
+
@connections = create_connections
|
30
|
+
draw_elements
|
34
31
|
|
35
32
|
@gv.save @dest_file, @options[:format]
|
36
33
|
end
|
37
34
|
|
38
35
|
private
|
39
36
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
@gv.node(t[:id], node_style)
|
48
|
-
end
|
37
|
+
def draw_elements
|
38
|
+
code = @layers.to_code if @layers
|
39
|
+
@connections.each do |c|
|
40
|
+
code << c.to_code
|
41
|
+
end if @connections
|
42
|
+
@gv.graph(&eval("proc {#{code}}"))
|
43
|
+
end
|
49
44
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
override_style(:node, node_style, v[:type])
|
58
|
-
@gv.subgraph "cluster#{id}" do
|
59
|
-
global label: layer_name
|
60
|
-
global DEFAULT_STYLE
|
61
|
-
node(v[:id], node_style)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
45
|
+
def create_layers(name = TOP_LAYER, source = @source)
|
46
|
+
return nil unless source && source.is_a?(Hash)
|
47
|
+
layer = Element::Layer.new(source, @style[:types])
|
48
|
+
layer.name = name
|
49
|
+
layer.layers = create_sub_layers(source)
|
50
|
+
layer.nodes = create_nodes(source)
|
51
|
+
layer
|
65
52
|
end
|
66
53
|
|
67
|
-
def
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
node = {
|
79
|
-
id: id, name: name, label: label,
|
80
|
-
ports: ports, type: type, url: url
|
81
|
-
}
|
82
|
-
built_nodes.merge!(name => node)
|
83
|
-
@nodes.merge!(name => node)
|
84
|
-
end if nodes
|
85
|
-
|
86
|
-
layers = layer[layer_name][:layers]
|
87
|
-
built_layers = {}
|
88
|
-
layers.each_pair do |k, v|
|
89
|
-
built_layers.merge!(build_nodes(k => v))
|
90
|
-
end if layers
|
91
|
-
built_nodes = { layer_name => built_nodes, layers: built_layers }
|
54
|
+
def create_sub_layers(source)
|
55
|
+
return nil unless source && source[:layers]
|
56
|
+
sub_layers = []
|
57
|
+
source[:layers].each do |l|
|
58
|
+
return nil unless l.is_a?(Hash)
|
59
|
+
name = l.keys.first
|
60
|
+
src = l[name]
|
61
|
+
sub_layer = create_layers(name, src) if src
|
62
|
+
sub_layers << sub_layer if sub_layer
|
63
|
+
end
|
64
|
+
sub_layers
|
92
65
|
end
|
93
66
|
|
94
|
-
def
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
label << "<tr border='1'><td border='1' colspan=\"#{opt[:ports].size}\">#{opt[:name]}</td></tr>"
|
67
|
+
def create_nodes(source)
|
68
|
+
return nil unless source && source[:nodes]
|
69
|
+
nodes = []
|
70
|
+
source[:nodes].each do |n|
|
71
|
+
return nil unless n.is_a?(Hash)
|
72
|
+
node = Element::Node.new(n.values.first, @style[:types])
|
73
|
+
node.name = n.keys.first
|
74
|
+
@nodes[node.name] = node.id
|
75
|
+
nodes << node
|
104
76
|
end
|
105
|
-
|
77
|
+
nodes
|
106
78
|
end
|
107
79
|
|
108
80
|
def create_connections
|
109
|
-
return
|
110
|
-
|
81
|
+
return unless @source[:connections]
|
82
|
+
connections = []
|
111
83
|
@source[:connections].each do |c|
|
112
|
-
from_name, from_port = c[:from].
|
113
|
-
to_name, to_port = c[:to].
|
114
|
-
|
115
|
-
|
84
|
+
from_name, from_port = c[:from].split(':')
|
85
|
+
to_name, to_port = c[:to].split(':')
|
86
|
+
|
87
|
+
from_name = from_name.to_sym
|
88
|
+
to_name = to_name.to_sym
|
89
|
+
return unless node_exist?(from_name) && node_exist?(to_name)
|
116
90
|
|
117
|
-
|
118
|
-
|
119
|
-
line_style = override_style(:line, {}, :"#{c[:type]}")
|
91
|
+
connection = Element::Connection.new({}, @style[:types])
|
92
|
+
c.each_pair { |k, v| connection[k.to_sym] = v }
|
120
93
|
|
121
|
-
|
122
|
-
|
94
|
+
from = from_port ? "#{@nodes[from_name]}:p#{from_port}" : @nodes[from_name]
|
95
|
+
to = to_port ? "#{@nodes[to_name]}:p#{to_port}" : @nodes[to_name]
|
96
|
+
|
97
|
+
connection.from = from
|
98
|
+
connection.to = to
|
99
|
+
connections << connection
|
100
|
+
end
|
101
|
+
connections
|
102
|
+
end
|
103
|
+
|
104
|
+
def node_exist?(name)
|
105
|
+
return false unless name
|
106
|
+
if @nodes[name]
|
107
|
+
true
|
108
|
+
else
|
109
|
+
puts "No #{name} exists"
|
110
|
+
false
|
123
111
|
end
|
124
112
|
end
|
125
113
|
|
126
|
-
def
|
127
|
-
|
128
|
-
|
129
|
-
case type
|
130
|
-
when :line
|
131
|
-
DEFAULT_LINE_STYLE
|
132
|
-
when :node
|
133
|
-
DEFAULT_NODE_STYLE
|
134
|
-
else
|
135
|
-
DEFAULT_STYLE
|
136
|
-
end
|
137
|
-
origin = {} unless origin
|
138
|
-
return default.merge(origin) unless style_type
|
139
|
-
style = @style[:types][style_type] if @style[:types]
|
140
|
-
style ||= {}
|
141
|
-
default.merge(origin).merge(style)
|
114
|
+
def node_id(name)
|
115
|
+
return nil unless node_exist?(name)
|
116
|
+
@nodes[name.to_sym]
|
142
117
|
end
|
143
118
|
end
|
144
119
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'network_drawer'
|
2
|
+
|
3
|
+
module NetworkDrawer
|
4
|
+
module Element
|
5
|
+
# Replesent of connection
|
6
|
+
class Connection < Element
|
7
|
+
DEFAULT_STYLE = {}
|
8
|
+
|
9
|
+
def initialize(initial_values = {}, style = {})
|
10
|
+
super
|
11
|
+
@default_style = DEFAULT_STYLE
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_code
|
15
|
+
style = style(self.type).dup
|
16
|
+
style.merge!(self.to_hash)
|
17
|
+
cid = "#{self.from}_#{self.to}_#{self.id}".gsub('/', '').to_sym
|
18
|
+
"edge(:\"#{cid}\", #{style})\n"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'network_drawer'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
require 'gviz'
|
5
|
+
|
6
|
+
module NetworkDrawer
|
7
|
+
module Element
|
8
|
+
# Replesent of element
|
9
|
+
class Element < OpenStruct
|
10
|
+
DEFAULT_STYLE = {}
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def generate_id
|
14
|
+
@ids ? @ids += 1 : @ids = 0
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(initial_values = {}, style = {})
|
19
|
+
super(initial_values)
|
20
|
+
self.id = self.class.generate_id
|
21
|
+
@default_style = DEFAULT_STYLE
|
22
|
+
@style = style
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_hash
|
26
|
+
hash = {}
|
27
|
+
self.each_pair do |k, v|
|
28
|
+
hash.merge!(k.to_sym => v) unless k.to_sym == name
|
29
|
+
end
|
30
|
+
hash
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def style(type)
|
36
|
+
# TODO: select multiple types
|
37
|
+
type = type.to_sym if type
|
38
|
+
style = @style ? @style[type] : {}
|
39
|
+
style ? @default_style.merge(style) : @default_style
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'network_drawer'
|
2
|
+
|
3
|
+
module NetworkDrawer
|
4
|
+
module Element
|
5
|
+
# Replesent of layer
|
6
|
+
class Layer < Element
|
7
|
+
DEFAULT_STYLE = { fontname: 'Helvetica' }
|
8
|
+
|
9
|
+
def initialize(initial_values = {}, style = {})
|
10
|
+
super
|
11
|
+
@default_style = DEFAULT_STYLE
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_code
|
15
|
+
style = style(self.type).dup
|
16
|
+
style.merge!(self.to_hash)
|
17
|
+
style.delete(:layers)
|
18
|
+
style.delete(:nodes)
|
19
|
+
style.delete(:connections)
|
20
|
+
label = self.name unless Diagram::TOP_LAYER == self.name
|
21
|
+
|
22
|
+
node_code = ''
|
23
|
+
nodes.each { |n| node_code += n.to_code + "\n" } if nodes
|
24
|
+
layer_code = ''
|
25
|
+
layers.each { |l| layer_code += l.to_code + "\n" } if layers
|
26
|
+
|
27
|
+
code = ''
|
28
|
+
if Diagram::TOP_LAYER == self.name
|
29
|
+
code = <<-EOF
|
30
|
+
global(#{style})
|
31
|
+
#{node_code}
|
32
|
+
#{layer_code}
|
33
|
+
EOF
|
34
|
+
else
|
35
|
+
code = <<-EOF
|
36
|
+
subgraph "cluster_#{self.name}" do
|
37
|
+
global label: "#{label}"
|
38
|
+
global(#{style})
|
39
|
+
#{node_code}
|
40
|
+
#{layer_code}
|
41
|
+
end
|
42
|
+
EOF
|
43
|
+
end
|
44
|
+
code
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'network_drawer'
|
2
|
+
|
3
|
+
module NetworkDrawer
|
4
|
+
module Element
|
5
|
+
# Replesent of node
|
6
|
+
class Node < Element
|
7
|
+
DEFAULT_STYLE = { fontname: 'Helvetica', shape: 'box' }
|
8
|
+
|
9
|
+
def initialize(initial_values = {}, style = {})
|
10
|
+
super
|
11
|
+
@default_style = DEFAULT_STYLE
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_code
|
15
|
+
style = style(self.type).dup
|
16
|
+
style.merge!(self.to_hash)
|
17
|
+
style.merge!(label: build_label, tooltip: self.name, URL: self.url )
|
18
|
+
style.merge!(ports: nil)
|
19
|
+
"node(:\"#{self.id}\", #{style})"
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def build_label
|
25
|
+
if self.ports && self.ports.size > 0
|
26
|
+
label = "<tr border='1'>"
|
27
|
+
self.ports.each_with_index do |p, j|
|
28
|
+
label << "<td border='1' port=\"p#{p.gsub('/', '')}\">#{p}</td>"
|
29
|
+
end
|
30
|
+
label << '</tr>'
|
31
|
+
label << "<tr border='1'><td border='1' colspan=\"#{self.ports.size}\">#{self.name}</td></tr>"
|
32
|
+
else
|
33
|
+
label = "<tr border='1'><td>#{self.name}</td></tr>"
|
34
|
+
end
|
35
|
+
"<table border='0'>#{label}</table>"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -1,10 +1,44 @@
|
|
1
1
|
require 'json'
|
2
|
+
require 'yaml'
|
2
3
|
|
3
4
|
module NetworkDrawer
|
4
5
|
# Replesent of source file
|
5
6
|
class Source
|
6
|
-
def self.read(file_name
|
7
|
-
|
7
|
+
def self.read(file_name)
|
8
|
+
source = {}
|
9
|
+
case file_type(file_name)
|
10
|
+
when :json
|
11
|
+
source = JSON.parse(File.read(file_name), symbolize_names: true)
|
12
|
+
when :yaml
|
13
|
+
source = symbolize(YAML.load(File.read(file_name)))
|
14
|
+
else
|
15
|
+
puts 'Incorrect file type'
|
16
|
+
exit 1
|
17
|
+
end
|
18
|
+
source
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.file_type(file_name)
|
22
|
+
return nil unless file_name
|
23
|
+
case file_name
|
24
|
+
when /\.json$/
|
25
|
+
:json
|
26
|
+
when /\.ya?ml$/
|
27
|
+
:yaml
|
28
|
+
else
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
def self.symbolize(obj)
|
33
|
+
return obj.inject({}) do |memo, (k, v)|
|
34
|
+
memo[k.to_sym] = symbolize(v)
|
35
|
+
memo
|
36
|
+
end if obj.is_a? Hash
|
37
|
+
return obj.inject([]) do |memo, v|
|
38
|
+
memo << symbolize(v)
|
39
|
+
memo
|
40
|
+
end if obj.is_a? Array
|
41
|
+
return obj
|
8
42
|
end
|
9
43
|
end
|
10
44
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: network_drawer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hiroshi Ota
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-03-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: gviz
|
@@ -108,16 +108,19 @@ files:
|
|
108
108
|
- README.md
|
109
109
|
- Rakefile
|
110
110
|
- bin/network_drawer
|
111
|
-
- examples/simple.dot
|
112
111
|
- examples/simple.json
|
113
112
|
- examples/simple.png
|
114
113
|
- examples/simple.svg
|
114
|
+
- examples/simple.yml
|
115
115
|
- examples/simple_style.json
|
116
116
|
- lib/network_drawer.rb
|
117
117
|
- lib/network_drawer/cli.rb
|
118
118
|
- lib/network_drawer/diagram.rb
|
119
|
+
- lib/network_drawer/element/connection.rb
|
120
|
+
- lib/network_drawer/element/element.rb
|
121
|
+
- lib/network_drawer/element/layer.rb
|
122
|
+
- lib/network_drawer/element/node.rb
|
119
123
|
- lib/network_drawer/source.rb
|
120
|
-
- lib/network_drawer/style.rb
|
121
124
|
- lib/network_drawer/version.rb
|
122
125
|
- network_drawer.gemspec
|
123
126
|
homepage: https://github.com/otahi/network_drawer
|
data/examples/simple.dot
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
digraph simple {
|
2
|
-
subgraph cluster1 {
|
3
|
-
label="Web";
|
4
|
-
fontname="Helvetica";
|
5
|
-
3[fontname="Helvetica",shape="box",label=<<table border='0'><tr border='1'><td border='1' port="p80tcp">80/tcp</td><td border='1' port="p443tcp">443/tcp</td></tr><tr border='1'><td border='1' colspan="2">WebLB</td></tr></table>>,tooltip="WebLB",URL="https://github.com/otahi/network_drawer/",style="rounded,filled,dotted",fillcolor="azure"];
|
6
|
-
}
|
7
|
-
subgraph cluster1 {
|
8
|
-
label="Web";
|
9
|
-
fontname="Helvetica";
|
10
|
-
4[fontname="Helvetica",shape="box",label=<<table border='0'><tr border='1'><td border='1' port="p80tcp">80/tcp</td></tr><tr border='1'><td border='1' colspan="1">Web001</td></tr></table>>,tooltip="Web001",URL=""];
|
11
|
-
}
|
12
|
-
subgraph cluster1 {
|
13
|
-
label="Web";
|
14
|
-
fontname="Helvetica";
|
15
|
-
5[fontname="Helvetica",shape="box",label=<<table border='0'><tr border='1'><td border='1' port="p80tcp">80/tcp</td></tr><tr border='1'><td border='1' colspan="1">Web002</td></tr></table>>,tooltip="Web002",URL=""];
|
16
|
-
}
|
17
|
-
subgraph cluster3 {
|
18
|
-
label="App";
|
19
|
-
fontname="Helvetica";
|
20
|
-
6[fontname="Helvetica",shape="box",label=<<table border='0'><tr border='1'><td border='1' port="p80tcp">80/tcp</td><td border='1' port="p25tcp">25/tcp</td></tr><tr border='1'><td border='1' colspan="2">AppLB</td></tr></table>>,tooltip="AppLB",URL="",style="rounded,filled,dotted",fillcolor="azure"];
|
21
|
-
}
|
22
|
-
subgraph cluster3 {
|
23
|
-
label="App";
|
24
|
-
fontname="Helvetica";
|
25
|
-
7[fontname="Helvetica",shape="box",label=<<table border='0'><tr border='1'><td border='1' port="p80tcp">80/tcp</td><td border='1' port="p25tcp">25/tcp</td></tr><tr border='1'><td border='1' colspan="2">App001</td></tr></table>>,tooltip="App001",URL=""];
|
26
|
-
}
|
27
|
-
subgraph cluster3 {
|
28
|
-
label="App";
|
29
|
-
fontname="Helvetica";
|
30
|
-
8[fontname="Helvetica",shape="box",label=<<table border='0'><tr border='1'><td border='1' port="p80tcp">80/tcp</td><td border='1' port="p25tcp">25/tcp</td></tr><tr border='1'><td border='1' colspan="2">App002</td></tr></table>>,tooltip="App002",URL=""];
|
31
|
-
}
|
32
|
-
rankdir="TB";
|
33
|
-
fontname="Helvetica";
|
34
|
-
1[fontname="Helvetica",shape="box",label=<<table border='0'><tr border='1'><td>Browser</td></tr></table>>,tooltip="Browser",URL=""];
|
35
|
-
2[fontname="Helvetica",shape="box",label=<<table border='0'><tr border='1'><td>Mail Server</td></tr></table>>,tooltip="Mail Server",URL=""];
|
36
|
-
3;
|
37
|
-
6;
|
38
|
-
4;
|
39
|
-
5;
|
40
|
-
7;
|
41
|
-
8;
|
42
|
-
1 -> 3:p80tcp[color="blue"];
|
43
|
-
1 -> 3:p443tcp;
|
44
|
-
2 -> 6:p25tcp[color="green"];
|
45
|
-
3 -> 4:p80tcp[color="blue"];
|
46
|
-
3 -> 5:p80tcp[color="blue"];
|
47
|
-
4 -> 6:p80tcp[color="blue"];
|
48
|
-
5 -> 6:p80tcp[color="blue"];
|
49
|
-
6 -> 7:p25tcp[color="green"];
|
50
|
-
6 -> 7:p80tcp[color="blue"];
|
51
|
-
6 -> 8:p25tcp[color="green"];
|
52
|
-
6 -> 8:p80tcp[color="blue"];
|
53
|
-
}
|
data/lib/network_drawer/style.rb
DELETED