network_drawer 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/network_drawer.svg)](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