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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 62b2a058777853b011aa999b5bbfaff1f5aea5e9
4
- data.tar.gz: ca9f5bdc9aaa639146504074fa6b2d769ecf9656
3
+ metadata.gz: 8e3fd2565dcf2fc91d794f85263bfb54214f6730
4
+ data.tar.gz: 1f7503b24294cec4c9bf6d34cae092d4a2efcb2d
5
5
  SHA512:
6
- metadata.gz: e6368873678680cf9cb5c72f6c666e7f453fe992ce3c8659b9b7fab18eedff3157f7e01ac41c8cbe5d41dca0338e241f101217efd42e2a7258c503013a6eb600
7
- data.tar.gz: 8a6ede793ae512557266d3e48591e77fe55609962c686dd71bff6c07e2cee18eff3a664491225ca47ab952d6bb4bbfe9d4b3cd1246dc598c28b02eecf2a4036d
6
+ metadata.gz: 5a79d2f85c393a680bc50ee2552f81cffed56741570cd6adc3a81dc0058a76bb480f7316194f1aeeb2286e6f0c352c5235b9521e750b04549ceacdf2a94b4723
7
+ data.tar.gz: eef66c5545b072c38df3e58d9f61822510febc96063022b9cb87dbb5bac75b88e7f56d766172930ab5c73c8c0819cdc4b6511b7ac4362e9bf45c467f9ecba1af
data/.gitignore CHANGED
@@ -12,4 +12,5 @@
12
12
  *.so
13
13
  *.o
14
14
  *.a
15
+ *.dot
15
16
  mkmf.log
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 -y install graphviz
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
- You can draw a network diagram with specified style and png format:
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
- You can draw a network diagram with specified style and png format:
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
 
@@ -1,26 +1,44 @@
1
1
  {
2
- "layers": {
3
- "Web": {
4
- "nodes": [
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
- "WebLB": {
7
- "ports": ["80/tcp", "443/tcp"],
8
- "type": "LB",
9
- "url": "https://github.com/otahi/network_drawer/"
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
- "App": {
17
- "nodes": [
18
- { "AppLB": { "ports": ["80/tcp", "25/tcp"], "type": "LB" } },
19
- { "App001": { "ports": ["80/tcp", "25/tcp"] } },
20
- { "App002": { "ports": ["80/tcp", "25/tcp"] } }
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" }
@@ -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="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 456)">
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="clust1" class="cluster"><title>cluster1</title>
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="clust2" class="cluster"><title>cluster3</title>
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
- <!-- 3 -->
21
- <g id="node1" class="node"><title>3</title>
22
- <g id="a_node1"><a xlink:href="https://github.com/otahi/network_drawer/" xlink:title="WebLB">
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
- <!-- 4 -->
34
- <g id="node2" class="node"><title>4</title>
35
- <g id="a_node2"><a xlink:title="Web001">
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
- <!-- 3&#45;&gt;4 -->
45
- <g id="edge4" class="edge"><title>3&#45;&gt;4:p80tcp</title>
44
+ <!-- 0&#45;&gt;1 -->
45
+ <g id="3" class="edge"><title>0&#45;&gt;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
- <!-- 5 -->
50
- <g id="node3" class="node"><title>5</title>
51
- <g id="a_node3"><a xlink:title="Web002">
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
- <!-- 3&#45;&gt;5 -->
61
- <g id="edge5" class="edge"><title>3&#45;&gt;5:p80tcp</title>
60
+ <!-- 0&#45;&gt;2 -->
61
+ <g id="4" class="edge"><title>0&#45;&gt;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
- <!-- 6 -->
66
- <g id="node4" class="node"><title>6</title>
67
- <g id="a_node4"><a xlink:title="AppLB">
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
- <!-- 4&#45;&gt;6 -->
79
- <g id="edge6" class="edge"><title>4&#45;&gt;6:p80tcp</title>
78
+ <!-- 1&#45;&gt;3 -->
79
+ <g id="5" class="edge"><title>1&#45;&gt;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
- <!-- 5&#45;&gt;6 -->
84
- <g id="edge7" class="edge"><title>5&#45;&gt;6:p80tcp</title>
83
+ <!-- 2&#45;&gt;3 -->
84
+ <g id="6" class="edge"><title>2&#45;&gt;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
- <!-- 7 -->
89
- <g id="node5" class="node"><title>7</title>
90
- <g id="a_node5"><a xlink:title="App001">
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
- <!-- 6&#45;&gt;7 -->
102
- <g id="edge8" class="edge"><title>6&#45;&gt;7:p25tcp</title>
101
+ <!-- 3&#45;&gt;4 -->
102
+ <g id="7" class="edge"><title>3&#45;&gt;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
- <!-- 6&#45;&gt;7 -->
107
- <g id="edge9" class="edge"><title>6&#45;&gt;7:p80tcp</title>
106
+ <!-- 3&#45;&gt;4 -->
107
+ <g id="8" class="edge"><title>3&#45;&gt;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
- <!-- 8 -->
112
- <g id="node6" class="node"><title>8</title>
113
- <g id="a_node6"><a xlink:title="App002">
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
- <!-- 6&#45;&gt;8 -->
125
- <g id="edge10" class="edge"><title>6&#45;&gt;8:p25tcp</title>
124
+ <!-- 3&#45;&gt;5 -->
125
+ <g id="9" class="edge"><title>3&#45;&gt;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
- <!-- 6&#45;&gt;8 -->
130
- <g id="edge11" class="edge"><title>6&#45;&gt;8:p80tcp</title>
129
+ <!-- 3&#45;&gt;5 -->
130
+ <g id="10" class="edge"><title>3&#45;&gt;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
- <!-- 1 -->
135
- <g id="node7" class="node"><title>1</title>
136
- <g id="a_node7"><a xlink:title="Browser">
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
- <!-- 1&#45;&gt;3 -->
143
- <g id="edge1" class="edge"><title>1&#45;&gt;3:p80tcp</title>
142
+ <!-- 6&#45;&gt;0 -->
143
+ <g id="0" class="edge"><title>6&#45;&gt;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
- <!-- 1&#45;&gt;3 -->
148
- <g id="edge2" class="edge"><title>1&#45;&gt;3:p443tcp</title>
147
+ <!-- 6&#45;&gt;0 -->
148
+ <g id="1" class="edge"><title>6&#45;&gt;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
- <!-- 2 -->
153
- <g id="node8" class="node"><title>2</title>
154
- <g id="a_node8"><a xlink:title="Mail Server">
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
- <!-- 2&#45;&gt;6 -->
161
- <g id="edge3" class="edge"><title>2&#45;&gt;6:p25tcp</title>
160
+ <!-- 7&#45;&gt;3 -->
161
+ <g id="2" class="edge"><title>7&#45;&gt;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>
@@ -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
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "types": {
3
+ "WEB": { "style": "rounded,filled,dotted", "fillcolor": "azure" },
3
4
  "LB": { "style": "rounded,filled,dotted", "fillcolor": "azure" },
4
5
  "HTTP": { "color": "blue" },
5
6
  "SMTP": { "color": "green" }
@@ -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'
@@ -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 = { style: Style.read(options[:style]) }
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
- dia = new(source, dest_file, options)
14
- dia.draw
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
- @gv.global(rankdir: 'TB')
31
- @gv.global(DEFAULT_STYLE)
32
- create_nodes
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 create_nodes
41
- built_nodes = build_nodes(TOP_LAYER => @source)
42
- built_nodes[TOP_LAYER].each_value do |t|
43
- @gv.global DEFAULT_STYLE
44
- node_style = { label: t[:label], tooltip: t[:name], URL: t[:url] }
45
- node_style =
46
- override_style(:node, node_style, t[:type])
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
- built_nodes[:layers].each_pair do |n, l|
51
- layer_name = n
52
- id = "#{@layers.size + 1}".to_sym
53
- @layers.merge!(layer_name => id)
54
- l.each_value do |v|
55
- node_style = { label: v[:label], tooltip: v[:name], URL: v[:url] }
56
- node_style =
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 build_nodes(layer)
68
- layer_name = layer.keys.first
69
- nodes = layer[layer_name][:nodes]
70
- built_nodes = {}
71
- nodes.each_with_index do |s, i|
72
- id = "#{@nodes.size + 1}".to_sym
73
- name = s.keys.first
74
- ports = s[name][:ports] ? s[name][:ports] : []
75
- url = s[name][:url] ? s[name][:url] : nil
76
- label = build_node_label(name: name, ports: ports)
77
- type = s[name][:type] ? s[name][:type].to_sym : nil
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 build_node_label(opt = {})
95
- if opt[:ports].empty?
96
- label = "<tr border='1'><td>#{opt[:name]}</td></tr>"
97
- else
98
- label = "<tr border='1'>"
99
- opt[:ports].each_with_index do |p, j|
100
- label << "<td border='1' port=\"p#{p.gsub('/', '')}\">#{p}</td>"
101
- end
102
- label << '</tr>'
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
- "<table border='0'>#{label}</table>"
77
+ nodes
106
78
  end
107
79
 
108
80
  def create_connections
109
- return if @source[:connections].nil?
110
- seq = 0
81
+ return unless @source[:connections]
82
+ connections = []
111
83
  @source[:connections].each do |c|
112
- from_name, from_port = c[:from].to_s.split(':')
113
- to_name, to_port = c[:to].to_s.split(':')
114
- from_id = @nodes[from_name.to_sym][:id]
115
- to_id = @nodes[to_name.to_sym][:id]
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
- from = from_port ? "#{from_id}:p#{from_port}" : from_id
118
- to = to_port ? "#{to_id}:p#{to_port}" : to_id
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
- @gv.edge "#{from}_#{to}_#{seq}".gsub('/', '').to_sym, line_style
122
- seq += 1
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 override_style(type, origin, style_type)
127
-
128
- default =
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, type = :json)
7
- JSON.parse(File.read(file_name), symbolize_names: true)
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
@@ -1,3 +1,3 @@
1
1
  module NetworkDrawer
2
- VERSION = '0.1.0'
2
+ VERSION = '0.1.1'
3
3
  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.0
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-02-21 00:00:00.000000000 Z
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
@@ -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
- }
@@ -1,14 +0,0 @@
1
- require 'json'
2
-
3
- module NetworkDrawer
4
- # Replesent of style file
5
- class Style
6
- def self.read(file_name, type = :json)
7
- if file_name
8
- JSON.parse(File.read(file_name), symbolize_names: true)
9
- else
10
- {}
11
- end
12
- end
13
- end
14
- end