phut 0.6.11 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5e5e604f7bc0d9963062f263ad70e787deecffbb
4
- data.tar.gz: 9833f795bbfebd0d68dab1965573732b6dae5185
3
+ metadata.gz: 82a2560cbd23e1dc3c22c6e2ead56c91b07caa0a
4
+ data.tar.gz: d2593cbcab813501fa6f489a787ca6a7b3e07411
5
5
  SHA512:
6
- metadata.gz: 1d6cd03b04fb8e68d211d99f26c315311bead73316c99824537570799a99930e75c72cfa58b03496c71a0675e41a05fb97873cb2d8c5d161658a47733c3a541b
7
- data.tar.gz: 853ecb0045dce1c0784b7d1b53c42863650dd501793d1679e4053399134639712324d3d56e4549f7bdbd72a08f60aadf5babf48da448d5b88b57659bf1e889b0
6
+ metadata.gz: e9858a15cc20fa1017aa4ee1d0900186e9227b2dbbf29c8ac6c5b4b89cab7fd52cfaa28c8daa63e3a253b6fe8b2db17e26a0d620e110d3401705251c9799cf57
7
+ data.tar.gz: e5c3aa9720cc6901f9774485f40c218494c3a1a06f35da46d0a56ef1c7b0e443d9af91462c8f019f52a40cc2a5c1d3b3d48dcdaaaf77db8e1bdf9a05f93051a3
@@ -3,6 +3,11 @@
3
3
  ## develop (unreleased)
4
4
 
5
5
 
6
+ ## 0.7.0 (10/30/2015)
7
+ ### New features
8
+ * [#32](https://github.com/trema/phut/pull/32): Add netns directive.
9
+
10
+
6
11
  ## 0.6.11 (9/29/2015)
7
12
  ### Changes
8
13
  * [#30](https://github.com/trema/phut/issues/30): Support apt-installed rubies.
data/bin/phut CHANGED
@@ -13,6 +13,7 @@ $stdout.sync = true
13
13
 
14
14
  module Phut
15
15
  # /bin/phut command
16
+ # rubocop:disable ModuleLength
16
17
  module App
17
18
  extend GLI::App
18
19
 
@@ -129,6 +130,11 @@ module Phut
129
130
 
130
131
  default_command :shell
131
132
 
133
+ on_error do |e|
134
+ fail e
135
+ end
136
+
132
137
  exit run(ARGV)
133
138
  end
139
+ # rubocop:enable ModuleLength
134
140
  end
@@ -29,6 +29,7 @@ module Phut
29
29
  def update_connections
30
30
  update_vswitch_ports
31
31
  update_vhost_interfaces
32
+ update_netns_interfaces
32
33
  self
33
34
  end
34
35
 
@@ -40,15 +41,21 @@ module Phut
40
41
  @all.values.select { |each| each.is_a? Vhost }
41
42
  end
42
43
 
44
+ def netnss
45
+ @all.values.select { |each| each.is_a? Netns }
46
+ end
47
+
43
48
  def run
44
49
  @links.each(&:run)
45
50
  vhosts.each { |each| each.run vhosts }
51
+ netnss.each(&:run)
46
52
  vswitches.each(&:run)
47
53
  end
48
54
 
49
55
  def stop
50
56
  vswitches.each(&:maybe_stop)
51
57
  vhosts.each(&:maybe_stop)
58
+ netnss.each(&:maybe_stop)
52
59
  @links.each(&:maybe_stop)
53
60
  end
54
61
 
@@ -64,6 +71,11 @@ module Phut
64
71
  Vhost.new(attrs[:ip], attrs[:mac], attrs[:promisc], name, @logger)
65
72
  end
66
73
 
74
+ def add_netns(name, attrs)
75
+ check_name_conflict name
76
+ @all[name] = Netns.new(attrs, name, @logger)
77
+ end
78
+
67
79
  def add_link(name_a, name_b)
68
80
  @links << VirtualLink.new(name_a, name_b, @logger)
69
81
  end
@@ -97,6 +109,12 @@ module Phut
97
109
  end
98
110
  end
99
111
 
112
+ def update_netns_interfaces
113
+ netnss.each do |each|
114
+ each.network_device = find_network_device(each)
115
+ end
116
+ end
117
+
100
118
  def find_network_device(vhost)
101
119
  @links.each do |each|
102
120
  device = each.find_network_device(vhost)
@@ -0,0 +1,37 @@
1
+ require 'phut/null_logger'
2
+ require 'phut/shell_runner'
3
+
4
+ module Phut
5
+ # `ip netns ...` command runner
6
+ class Netns
7
+ include ShellRunner
8
+
9
+ attr_reader :name
10
+ attr_accessor :network_device
11
+
12
+ def initialize(options, name, logger = NullLogger.new)
13
+ @name = name
14
+ @options = options
15
+ @logger = logger
16
+ end
17
+
18
+ # rubocop:disable AbcSize
19
+ def run
20
+ sh "sudo ip netns add #{name}"
21
+ sh "sudo ip link set dev #{network_device} netns #{name}"
22
+ sh "sudo ip netns exec #{name} ifconfig lo 127.0.0.1"
23
+ sh "sudo ip netns exec #{name}"\
24
+ " ifconfig #{network_device} #{ip} netmask #{netmask}"
25
+ sh "sudo ip netns exec #{name} route add -net #{net} gw #{gateway}"
26
+ end
27
+ # rubocop:enable AbcSize
28
+
29
+ def maybe_stop
30
+ sh "sudo ip netns delete #{name}"
31
+ end
32
+
33
+ def method_missing(message, *_args)
34
+ @options.__send__ :[], message
35
+ end
36
+ end
37
+ end
@@ -1,3 +1,4 @@
1
+ require 'phut/netns'
1
2
  require 'phut/vhost'
2
3
  require 'phut/virtual_link'
3
4
 
@@ -75,6 +76,32 @@ module Phut
75
76
  end
76
77
  end
77
78
 
79
+ # The 'netns(name) { ...attributes... }' directive.
80
+ class NetnsDirective
81
+ def initialize(alias_name, &block)
82
+ @attributes = { name: alias_name }
83
+ instance_eval(&block)
84
+ end
85
+
86
+ def ip(value)
87
+ @attributes[:ip] = value
88
+ @attributes[:name] ||= value
89
+ end
90
+
91
+ def netmask(value)
92
+ @attributes[:netmask] = value
93
+ end
94
+
95
+ def route(options)
96
+ @attributes[:net] = options.fetch(:net)
97
+ @attributes[:gateway] = options.fetch(:gateway)
98
+ end
99
+
100
+ def [](key)
101
+ @attributes[key]
102
+ end
103
+ end
104
+
78
105
  def initialize(config)
79
106
  @config = config
80
107
  end
@@ -89,6 +116,11 @@ module Phut
89
116
  @config.add_vhost attrs[:name], attrs
90
117
  end
91
118
 
119
+ def netns(name, &block)
120
+ attrs = NetnsDirective.new(name, &block)
121
+ @config.add_netns attrs[:name], attrs
122
+ end
123
+
92
124
  def link(name_a, name_b)
93
125
  @config.add_link name_a, name_b
94
126
  end
@@ -1,4 +1,4 @@
1
1
  # Base module.
2
2
  module Phut
3
- VERSION = '0.6.11'
3
+ VERSION = '0.7.0'
4
4
  end
@@ -62,7 +62,7 @@ module Phut
62
62
  end
63
63
 
64
64
  def up?
65
- /^#{@device_a}\s+Link encap:Ethernet/ =~ `ifconfig -a` || false
65
+ /^#{@device_a}\s+Link encap:Ethernet/ =~ `LANG=C ifconfig -a` || false
66
66
  end
67
67
 
68
68
  def connect_to?(vswitch)
@@ -24,8 +24,8 @@ Gem::Specification.new do |gem|
24
24
  gem.required_ruby_version = '>= 2.0.0'
25
25
 
26
26
  gem.add_dependency 'gli', '~> 2.13.2'
27
- gem.add_dependency 'pio', '~> 0.27.0'
28
- gem.add_dependency 'pry', '~> 0.10.1'
27
+ gem.add_dependency 'pio', '~> 0.27.2'
28
+ gem.add_dependency 'pry', '~> 0.10.3'
29
29
 
30
30
  # Docs
31
31
  gem.add_development_dependency 'relish'
@@ -42,13 +42,13 @@ Gem::Specification.new do |gem|
42
42
  # Test
43
43
  gem.add_development_dependency 'aruba', '~> 0.8.1'
44
44
  gem.add_development_dependency 'codeclimate-test-reporter'
45
- gem.add_development_dependency 'coveralls', '~> 0.8.2'
46
- gem.add_development_dependency 'cucumber', '~> 2.0.2'
45
+ gem.add_development_dependency 'coveralls', '~> 0.8.3'
46
+ gem.add_development_dependency 'cucumber', '~> 2.1.0'
47
47
  gem.add_development_dependency 'flay', '~> 2.6.1'
48
48
  gem.add_development_dependency 'flog', '~> 4.3.2'
49
49
  gem.add_development_dependency 'rake'
50
- gem.add_development_dependency 'reek', '~> 3.3.1'
50
+ gem.add_development_dependency 'reek', '~> 3.5.0'
51
51
  gem.add_development_dependency 'rspec', '~> 3.3.0'
52
52
  gem.add_development_dependency 'rspec-given', '~> 3.7.1'
53
- gem.add_development_dependency 'rubocop', '~> 0.34.1'
53
+ gem.add_development_dependency 'rubocop', '~> 0.34.2'
54
54
  end
metadata CHANGED
@@ -1,323 +1,323 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: phut
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.11
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yasuhito Takamiya
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-29 00:00:00.000000000 Z
11
+ date: 2015-10-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: gli
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: 2.13.2
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: 2.13.2
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: pio
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.27.0
33
+ version: 0.27.2
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.27.0
40
+ version: 0.27.2
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: pry
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 0.10.1
47
+ version: 0.10.3
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ~>
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 0.10.1
54
+ version: 0.10.3
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: relish
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: yard
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ~>
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
75
  version: 0.8.7.6
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ~>
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: 0.8.7.6
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: byebug
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ~>
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
89
  version: 6.0.2
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ~>
94
+ - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: 6.0.2
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: guard
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ~>
101
+ - - "~>"
102
102
  - !ruby/object:Gem::Version
103
103
  version: 2.13.0
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - ~>
108
+ - - "~>"
109
109
  - !ruby/object:Gem::Version
110
110
  version: 2.13.0
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: guard-bundler
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - ~>
115
+ - - "~>"
116
116
  - !ruby/object:Gem::Version
117
117
  version: 2.1.0
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - ~>
122
+ - - "~>"
123
123
  - !ruby/object:Gem::Version
124
124
  version: 2.1.0
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: guard-cucumber
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - ~>
129
+ - - "~>"
130
130
  - !ruby/object:Gem::Version
131
131
  version: 1.6.0
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - ~>
136
+ - - "~>"
137
137
  - !ruby/object:Gem::Version
138
138
  version: 1.6.0
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: guard-rspec
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
- - - ~>
143
+ - - "~>"
144
144
  - !ruby/object:Gem::Version
145
145
  version: 4.6.4
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
- - - ~>
150
+ - - "~>"
151
151
  - !ruby/object:Gem::Version
152
152
  version: 4.6.4
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: guard-rubocop
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
- - - ~>
157
+ - - "~>"
158
158
  - !ruby/object:Gem::Version
159
159
  version: 1.2.0
160
160
  type: :development
161
161
  prerelease: false
162
162
  version_requirements: !ruby/object:Gem::Requirement
163
163
  requirements:
164
- - - ~>
164
+ - - "~>"
165
165
  - !ruby/object:Gem::Version
166
166
  version: 1.2.0
167
167
  - !ruby/object:Gem::Dependency
168
168
  name: aruba
169
169
  requirement: !ruby/object:Gem::Requirement
170
170
  requirements:
171
- - - ~>
171
+ - - "~>"
172
172
  - !ruby/object:Gem::Version
173
173
  version: 0.8.1
174
174
  type: :development
175
175
  prerelease: false
176
176
  version_requirements: !ruby/object:Gem::Requirement
177
177
  requirements:
178
- - - ~>
178
+ - - "~>"
179
179
  - !ruby/object:Gem::Version
180
180
  version: 0.8.1
181
181
  - !ruby/object:Gem::Dependency
182
182
  name: codeclimate-test-reporter
183
183
  requirement: !ruby/object:Gem::Requirement
184
184
  requirements:
185
- - - '>='
185
+ - - ">="
186
186
  - !ruby/object:Gem::Version
187
187
  version: '0'
188
188
  type: :development
189
189
  prerelease: false
190
190
  version_requirements: !ruby/object:Gem::Requirement
191
191
  requirements:
192
- - - '>='
192
+ - - ">="
193
193
  - !ruby/object:Gem::Version
194
194
  version: '0'
195
195
  - !ruby/object:Gem::Dependency
196
196
  name: coveralls
197
197
  requirement: !ruby/object:Gem::Requirement
198
198
  requirements:
199
- - - ~>
199
+ - - "~>"
200
200
  - !ruby/object:Gem::Version
201
- version: 0.8.2
201
+ version: 0.8.3
202
202
  type: :development
203
203
  prerelease: false
204
204
  version_requirements: !ruby/object:Gem::Requirement
205
205
  requirements:
206
- - - ~>
206
+ - - "~>"
207
207
  - !ruby/object:Gem::Version
208
- version: 0.8.2
208
+ version: 0.8.3
209
209
  - !ruby/object:Gem::Dependency
210
210
  name: cucumber
211
211
  requirement: !ruby/object:Gem::Requirement
212
212
  requirements:
213
- - - ~>
213
+ - - "~>"
214
214
  - !ruby/object:Gem::Version
215
- version: 2.0.2
215
+ version: 2.1.0
216
216
  type: :development
217
217
  prerelease: false
218
218
  version_requirements: !ruby/object:Gem::Requirement
219
219
  requirements:
220
- - - ~>
220
+ - - "~>"
221
221
  - !ruby/object:Gem::Version
222
- version: 2.0.2
222
+ version: 2.1.0
223
223
  - !ruby/object:Gem::Dependency
224
224
  name: flay
225
225
  requirement: !ruby/object:Gem::Requirement
226
226
  requirements:
227
- - - ~>
227
+ - - "~>"
228
228
  - !ruby/object:Gem::Version
229
229
  version: 2.6.1
230
230
  type: :development
231
231
  prerelease: false
232
232
  version_requirements: !ruby/object:Gem::Requirement
233
233
  requirements:
234
- - - ~>
234
+ - - "~>"
235
235
  - !ruby/object:Gem::Version
236
236
  version: 2.6.1
237
237
  - !ruby/object:Gem::Dependency
238
238
  name: flog
239
239
  requirement: !ruby/object:Gem::Requirement
240
240
  requirements:
241
- - - ~>
241
+ - - "~>"
242
242
  - !ruby/object:Gem::Version
243
243
  version: 4.3.2
244
244
  type: :development
245
245
  prerelease: false
246
246
  version_requirements: !ruby/object:Gem::Requirement
247
247
  requirements:
248
- - - ~>
248
+ - - "~>"
249
249
  - !ruby/object:Gem::Version
250
250
  version: 4.3.2
251
251
  - !ruby/object:Gem::Dependency
252
252
  name: rake
253
253
  requirement: !ruby/object:Gem::Requirement
254
254
  requirements:
255
- - - '>='
255
+ - - ">="
256
256
  - !ruby/object:Gem::Version
257
257
  version: '0'
258
258
  type: :development
259
259
  prerelease: false
260
260
  version_requirements: !ruby/object:Gem::Requirement
261
261
  requirements:
262
- - - '>='
262
+ - - ">="
263
263
  - !ruby/object:Gem::Version
264
264
  version: '0'
265
265
  - !ruby/object:Gem::Dependency
266
266
  name: reek
267
267
  requirement: !ruby/object:Gem::Requirement
268
268
  requirements:
269
- - - ~>
269
+ - - "~>"
270
270
  - !ruby/object:Gem::Version
271
- version: 3.3.1
271
+ version: 3.5.0
272
272
  type: :development
273
273
  prerelease: false
274
274
  version_requirements: !ruby/object:Gem::Requirement
275
275
  requirements:
276
- - - ~>
276
+ - - "~>"
277
277
  - !ruby/object:Gem::Version
278
- version: 3.3.1
278
+ version: 3.5.0
279
279
  - !ruby/object:Gem::Dependency
280
280
  name: rspec
281
281
  requirement: !ruby/object:Gem::Requirement
282
282
  requirements:
283
- - - ~>
283
+ - - "~>"
284
284
  - !ruby/object:Gem::Version
285
285
  version: 3.3.0
286
286
  type: :development
287
287
  prerelease: false
288
288
  version_requirements: !ruby/object:Gem::Requirement
289
289
  requirements:
290
- - - ~>
290
+ - - "~>"
291
291
  - !ruby/object:Gem::Version
292
292
  version: 3.3.0
293
293
  - !ruby/object:Gem::Dependency
294
294
  name: rspec-given
295
295
  requirement: !ruby/object:Gem::Requirement
296
296
  requirements:
297
- - - ~>
297
+ - - "~>"
298
298
  - !ruby/object:Gem::Version
299
299
  version: 3.7.1
300
300
  type: :development
301
301
  prerelease: false
302
302
  version_requirements: !ruby/object:Gem::Requirement
303
303
  requirements:
304
- - - ~>
304
+ - - "~>"
305
305
  - !ruby/object:Gem::Version
306
306
  version: 3.7.1
307
307
  - !ruby/object:Gem::Dependency
308
308
  name: rubocop
309
309
  requirement: !ruby/object:Gem::Requirement
310
310
  requirements:
311
- - - ~>
311
+ - - "~>"
312
312
  - !ruby/object:Gem::Version
313
- version: 0.34.1
313
+ version: 0.34.2
314
314
  type: :development
315
315
  prerelease: false
316
316
  version_requirements: !ruby/object:Gem::Requirement
317
317
  requirements:
318
- - - ~>
318
+ - - "~>"
319
319
  - !ruby/object:Gem::Version
320
- version: 0.34.1
320
+ version: 0.34.2
321
321
  description: A simple network emulator with capabilities similar to mininet.
322
322
  email:
323
323
  - yasuhito@gmail.com
@@ -328,12 +328,12 @@ extensions: []
328
328
  extra_rdoc_files:
329
329
  - README.md
330
330
  files:
331
- - .gitignore
332
- - .hound.yml
333
- - .rspec
334
- - .rubocop.yml
335
- - .ruby-version
336
- - .travis.yml
331
+ - ".gitignore"
332
+ - ".hound.yml"
333
+ - ".rspec"
334
+ - ".rubocop.yml"
335
+ - ".ruby-version"
336
+ - ".travis.yml"
337
337
  - CHANGELOG.md
338
338
  - CONTRIBUTING.md
339
339
  - Gemfile
@@ -355,6 +355,7 @@ files:
355
355
  - features/support/hooks.rb
356
356
  - lib/phut.rb
357
357
  - lib/phut/configuration.rb
358
+ - lib/phut/netns.rb
358
359
  - lib/phut/null_logger.rb
359
360
  - lib/phut/open_vswitch.rb
360
361
  - lib/phut/parser.rb
@@ -393,17 +394,17 @@ require_paths:
393
394
  - lib
394
395
  required_ruby_version: !ruby/object:Gem::Requirement
395
396
  requirements:
396
- - - '>='
397
+ - - ">="
397
398
  - !ruby/object:Gem::Version
398
399
  version: 2.0.0
399
400
  required_rubygems_version: !ruby/object:Gem::Requirement
400
401
  requirements:
401
- - - '>='
402
+ - - ">="
402
403
  - !ruby/object:Gem::Version
403
404
  version: '0'
404
405
  requirements: []
405
406
  rubyforge_project:
406
- rubygems_version: 2.0.14
407
+ rubygems_version: 2.4.6
407
408
  signing_key:
408
409
  specification_version: 4
409
410
  summary: Virtual network in seconds.