construqt 0.0.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.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/lib/construqt/addresses.rb +204 -0
  3. data/lib/construqt/bgps.rb +164 -0
  4. data/lib/construqt/cables.rb +47 -0
  5. data/lib/construqt/firewalls.rb +247 -0
  6. data/lib/construqt/flavour/ciscian/ciscian.rb +687 -0
  7. data/lib/construqt/flavour/ciscian/dialect_dlink-dgs15xx.rb +235 -0
  8. data/lib/construqt/flavour/ciscian/dialect_hp-2510g.rb +114 -0
  9. data/lib/construqt/flavour/delegates.rb +448 -0
  10. data/lib/construqt/flavour/flavour.rb +97 -0
  11. data/lib/construqt/flavour/mikrotik/flavour_mikrotik.rb +417 -0
  12. data/lib/construqt/flavour/mikrotik/flavour_mikrotik_bgp.rb +134 -0
  13. data/lib/construqt/flavour/mikrotik/flavour_mikrotik_interface.rb +79 -0
  14. data/lib/construqt/flavour/mikrotik/flavour_mikrotik_ipsec.rb +65 -0
  15. data/lib/construqt/flavour/mikrotik/flavour_mikrotik_result.rb +182 -0
  16. data/lib/construqt/flavour/mikrotik/flavour_mikrotik_schema.rb +355 -0
  17. data/lib/construqt/flavour/plantuml/plantuml.rb +462 -0
  18. data/lib/construqt/flavour/ubuntu/flavour_ubuntu.rb +381 -0
  19. data/lib/construqt/flavour/ubuntu/flavour_ubuntu_bgp.rb +117 -0
  20. data/lib/construqt/flavour/ubuntu/flavour_ubuntu_dns.rb +97 -0
  21. data/lib/construqt/flavour/ubuntu/flavour_ubuntu_firewall.rb +300 -0
  22. data/lib/construqt/flavour/ubuntu/flavour_ubuntu_ipsec.rb +144 -0
  23. data/lib/construqt/flavour/ubuntu/flavour_ubuntu_opvn.rb +60 -0
  24. data/lib/construqt/flavour/ubuntu/flavour_ubuntu_result.rb +537 -0
  25. data/lib/construqt/flavour/ubuntu/flavour_ubuntu_services.rb +115 -0
  26. data/lib/construqt/flavour/ubuntu/flavour_ubuntu_vrrp.rb +52 -0
  27. data/lib/construqt/flavour/unknown/unknown.rb +175 -0
  28. data/lib/construqt/hostid.rb +42 -0
  29. data/lib/construqt/hosts.rb +98 -0
  30. data/lib/construqt/interfaces.rb +166 -0
  31. data/lib/construqt/ipsecs.rb +64 -0
  32. data/lib/construqt/networks.rb +81 -0
  33. data/lib/construqt/regions.rb +32 -0
  34. data/lib/construqt/resource.rb +42 -0
  35. data/lib/construqt/services.rb +53 -0
  36. data/lib/construqt/tags.rb +61 -0
  37. data/lib/construqt/templates.rb +37 -0
  38. data/lib/construqt/tests/test_addresses.rb +50 -0
  39. data/lib/construqt/tests/test_bgps.rb +24 -0
  40. data/lib/construqt/tests/test_hostid.rb +32 -0
  41. data/lib/construqt/tests/test_hosts.rb +23 -0
  42. data/lib/construqt/tests/test_utils.rb +76 -0
  43. data/lib/construqt/users.rb +19 -0
  44. data/lib/construqt/util.rb +163 -0
  45. data/lib/construqt/version.rb +3 -0
  46. data/lib/construqt/vlans.rb +51 -0
  47. data/lib/construqt.rb +92 -0
  48. metadata +105 -0
@@ -0,0 +1,687 @@
1
+ module Construqt
2
+ module Flavour
3
+ module Ciscian
4
+ def self.name
5
+ 'ciscian'
6
+ end
7
+
8
+ Construqt::Flavour.add(self)
9
+
10
+ @dialects={}
11
+ def self.dialects
12
+ @dialects
13
+ end
14
+
15
+ def self.add_dialect(dialect)
16
+ @dialects[dialect.name] = dialect
17
+ end
18
+
19
+ class Result
20
+ attr_accessor :dialect,:host, :sections
21
+ def initialize(host)
22
+ @host = host
23
+ @sections = {}
24
+ throw "ciscian flavour can only be created with dialect" unless host.dialect
25
+ require_relative "dialect_#{host.dialect}.rb"
26
+ throw "cannot load dialect class #{host.dialect}" unless Ciscian.dialects[host.dialect]
27
+ self.dialect=Ciscian.dialects[host.dialect].new(self)
28
+ end
29
+
30
+ class Lines
31
+ class Line
32
+ attr_reader :to_s, :nr
33
+ def initialize(str, nr)
34
+ @to_s = str
35
+ @nr = nr
36
+ end
37
+ def <=>(other)
38
+ a = self.to_s
39
+ b = other.to_s
40
+ match_a=/^(.*[^\d])(\d+)$/.match(a)||[nil,a,1]
41
+ match_b=/^(.*[^\d])(\d+)$/.match(b)||[nil,b,1]
42
+ #puts match_a, match_b, a, b
43
+ ret = match_a[1]<=>match_b[1]
44
+ ret = match_a[2].to_i<=>match_b[2].to_i if ret==0
45
+ ret
46
+ end
47
+ # def hash
48
+ # self.to_s.hash
49
+ # end
50
+ end
51
+ def initialize(lines)
52
+ @lines = []
53
+ lines.each_with_index do |line, idx|
54
+ @lines << Line.new(line.strip, idx)
55
+ end
56
+ @pos = 0
57
+ end
58
+ def shift
59
+ @pos += 1
60
+ @lines[@pos-1]
61
+ end
62
+ end
63
+ def parse(lines)
64
+ lines = Lines.new(lines)
65
+ while line = lines.shift
66
+ parse_line(line, lines, self, self)
67
+ end
68
+ self
69
+ end
70
+
71
+ def self.normalize_section_key(key)
72
+ matchdata=key.match(/^\s*(no\s+|)(.*)/)
73
+ matchdata[2]
74
+ end
75
+
76
+ def self.starts_with_no(key)
77
+ return key.match(/^\s*no\s+/)
78
+ end
79
+
80
+ def parse_line(line, lines, section, result)
81
+ return if self.dialect.parse_line(line, lines, section, result)
82
+ [NestedSection, SingleValueVerb].find do |clazz|
83
+ clazz.parse_line(line, lines, section, result)
84
+ end
85
+ end
86
+
87
+ def commit
88
+ self.dialect.commit
89
+
90
+ block=[]
91
+ @sections.keys.sort.each do |key|
92
+ section = @sections[key]
93
+ block += section.serialize
94
+ end
95
+ Util.write_str(block.join("\n"), File.join(@host.name, "#{@host.fname||self.dialect.class.name}.cfg"))
96
+ end
97
+
98
+ def add(section, clazz=NestedSection)
99
+ throw "section is nil" unless section
100
+ section = Lines::Line.new(section, -1) unless section.kind_of?(Lines::Line)
101
+ section_key=Result.normalize_section_key(section.to_s)
102
+
103
+ @sections[section_key] ||= clazz.new(section_key)
104
+ if Result.starts_with_no(section.to_s)
105
+ @sections[section_key].no
106
+ end
107
+ yield(@sections[section_key]) if block_given?
108
+ @sections[section_key]
109
+ end
110
+
111
+ def self.compare(nu, old)
112
+ result = Result.new(nu.host)
113
+
114
+ nu_root=NestedSection.new("root")
115
+ nu_root.sections.merge!(nu.sections)
116
+ other_root=NestedSection.new("root")
117
+ other_root.sections.merge!(old.sections)
118
+
119
+ deltas=NestedSection.compare(nu_root, other_root)
120
+ throw "illegal state" if deltas.length != 1
121
+ result.sections = deltas[0]
122
+ result
123
+ end
124
+ end
125
+
126
+ class SingleValueVerb
127
+ attr_accessor :section,:value
128
+ def initialize(section)
129
+ self.section=section
130
+ end
131
+
132
+ def serialize
133
+ [[@no, section , value].compact.join(" ")]
134
+ end
135
+
136
+ def self.compare(nu, old)
137
+ return [nu] unless old
138
+ return [old.no] unless nu
139
+ return [nu] unless nu.serialize == old.serialize
140
+ [nil]
141
+ end
142
+
143
+ def add(value)
144
+ self.value=value
145
+ end
146
+
147
+ def no
148
+ @no="no"
149
+ self.value=nil
150
+ self
151
+ end
152
+
153
+ def self.parse_line(line, lines, section, result)
154
+ regexp = line.to_s.strip.end_with?("\"") ? /^(.*) (\"[^"]+\")$/ : /^(.*) ([^\s"]+)$/
155
+ if (line.to_s.strip =~ regexp)
156
+ section.add($1, Ciscian::SingleValueVerb).add($2)
157
+ else
158
+ section.add(line.to_s, Ciscian::SingleValueVerb)
159
+ end
160
+ end
161
+ end
162
+
163
+ class NestedSection
164
+ attr_accessor :section,:sections
165
+ def initialize(section)
166
+ self.sections={}
167
+ self.section=section
168
+ end
169
+
170
+ def add(verb, clazz = MultiValueVerb)
171
+ # if verb.respond_to?(:section_key)
172
+ # clazz=verb
173
+ # verb=clazz.section_key
174
+ # end
175
+ self.sections[Result.normalize_section_key(verb.to_s)] ||= clazz.new(verb)
176
+ end
177
+
178
+ def self.parse_line(line, lines, section, result)
179
+ #binding.pry if line.start_with?("interface")
180
+ if [/^\s*(no\s+|)interface/, /^\s*(no\s+|)vlan/].find{|i| line.to_s.match(i) }
181
+ resultline=Result::Lines::Line.new(result.dialect.clear_interface(line), line.nr)
182
+ section.add(resultline.to_s) do |_section|
183
+ while _line = lines.shift
184
+ break if result.dialect.block_end?(_line.to_s)
185
+ result.parse_line(_line, lines, _section, result)
186
+ end
187
+ end
188
+
189
+ if (matchdata = line.to_s.match(Construqt::Util::PORTS_DEF_REGEXP))
190
+ ports = Construqt::Util::expandRangeDefinition(matchdata[0])
191
+ if (ports.length>1)
192
+ section_to_split=section.sections.delete(resultline.to_s)
193
+ ports.each do |port|
194
+ section.add(line.to_s.gsub(/#{Construqt::Util::PORTS_DEF_REGEXP}/, port)) do |_section|
195
+ _section.sections.merge!(section_to_split.sections)
196
+ end
197
+ end
198
+ end
199
+ end
200
+ return true
201
+ end
202
+ end
203
+
204
+ def render_verbs(verbs)
205
+ block=[]
206
+ sections.keys.sort.each do |key|
207
+ verb = sections[key]
208
+ block << verb.serialize.map{|i| " #{i}"}
209
+ end
210
+ block
211
+ end
212
+
213
+ def no
214
+ @no="no "
215
+ @sections={}
216
+ self
217
+ end
218
+
219
+ def no?
220
+ @no
221
+ end
222
+
223
+ def serialize
224
+ block=[]
225
+ block << "#{@no}#{section.to_s}"
226
+ unless (@no)
227
+ block += render_verbs(self.sections)
228
+ block << "exit"
229
+ end
230
+ block
231
+ end
232
+
233
+ def self.compare(nu, old)
234
+ return [nu] unless old
235
+ return [old.no] unless nu
236
+ throw "classes must match #{nu.class.name} != #{old.class.name}" unless nu.class == old.class
237
+ if (nu.serialize==old.serialize)
238
+ return [nil]
239
+ else
240
+ if (nu.no?)
241
+ return [nu]
242
+ else
243
+ delta = nu.class.new(nu.section)
244
+ (nu.sections.keys + old.sections.keys).sort.each do |k,v|
245
+ nu_section=nu.sections[k]
246
+ old_section=old.sections[k]
247
+ comps = (nu_section||old_section).class.compare(nu_section, old_section)
248
+ throw "class #{(nu_section||old_section).class.name} returns illegal nil in compare method" unless comps
249
+ comps.compact.each do |comp|
250
+ delta.sections[comp.section] = comp
251
+ end
252
+ end
253
+ return [delta]
254
+ end
255
+ end
256
+ end
257
+ end
258
+
259
+ class MultiValueVerb
260
+ attr_accessor :section,:values
261
+ def initialize(section)
262
+ self.section=section
263
+ self.values = []
264
+ end
265
+
266
+ def add(value)
267
+ self.values << value
268
+ self
269
+ end
270
+
271
+ def no
272
+ @no="no "
273
+ self
274
+ end
275
+
276
+ def serialize
277
+ if @no
278
+ ["#{@no}#{section}"]
279
+ else
280
+ ["#{section} #{values.join(",")}"]
281
+ end
282
+ end
283
+
284
+ def self.compare(nu, old)
285
+ return [nu] unless old
286
+ return [old.no] unless nu
287
+ throw "classes must match #{nu.class.name} != #{old.class.name}" unless nu.class == old.class
288
+ if (nu.serialize==old.serialize)
289
+ [nil]
290
+ else
291
+ [nu]
292
+ end
293
+ end
294
+ end
295
+
296
+ class RangeVerb
297
+ attr_accessor :section,:values
298
+ def initialize(section)
299
+ self.section=section
300
+ self.values = []
301
+ end
302
+
303
+ def add(value)
304
+ throw "must be a number \'#{value}\'" unless /^\d+$/.match(value.to_s)
305
+ self.values << value.to_i
306
+ self
307
+ end
308
+
309
+ def no
310
+ @no="no "
311
+ self
312
+ end
313
+
314
+ def self.compare(nu, old)
315
+ return [nu] unless old
316
+ return [old.no] unless nu
317
+ throw "classes must match #{nu.class.name} != #{old.class.name}" unless nu.class == old.class
318
+ if (nu.serialize==old.serialize)
319
+ [nil]
320
+ else
321
+ [nu]
322
+ end
323
+ end
324
+
325
+ def serialize
326
+ if @no
327
+ ["#{@no}#{section}"]
328
+ else
329
+ ["#{section} #{Construqt::Util.createRangeDefinition(values)}"]
330
+ end
331
+ end
332
+ end
333
+
334
+ class PatternBasedVerb
335
+ attr_accessor :section, :changes
336
+
337
+ def initialize(section)
338
+ self.section=section
339
+ self.changes=[]
340
+ end
341
+
342
+ def add(entry)
343
+ changes << entry
344
+ self
345
+ end
346
+
347
+ def self.invert(a)
348
+ return a.gsub(/\+/,"-") if a.match(/\+/)
349
+ return a.gsub(/\-/,"+") if a.match(/\-/)
350
+ throw "cannot invert #{a}"
351
+ end
352
+
353
+ def self.variables(patterns)
354
+ variables=[]
355
+ patterns.each do |pattern|
356
+ variables+=find_variables(pattern)
357
+ end
358
+ return variables
359
+ end
360
+
361
+ def self.find_variables(pattern)
362
+ return pattern.scan(/{[^}]+}/)
363
+ end
364
+
365
+ def self.parse_line(line, lines, section, result)
366
+ entry=matches(self.patterns, line.to_s)
367
+ return false unless entry
368
+ section.add(self.section, self).add(entry)
369
+ return true
370
+ end
371
+
372
+ def self.find_regex(varname)
373
+ return nil
374
+ end
375
+
376
+ def self.extract_varname(variable)
377
+ matchdata=variable.match(/{(\+|\-|\=|\*)([^}]+)}/)
378
+ throw "could not extract varname from #{variable}" unless matchdata
379
+ return matchdata[2]
380
+ end
381
+
382
+ def self.matches(patterns, line)
383
+ patterns.each do |pattern|
384
+ variables = find_variables(pattern)
385
+ regex=pattern
386
+ variables.each do |var|
387
+ var_regex = find_regex(extract_varname(var))
388
+ var_regex = "#{Construqt::Util::PORTS_DEF_REGEXP}" unless var_regex
389
+ regex=regex.gsub(var, var_regex)
390
+ end
391
+ regex=regex.gsub(" ", "\\s+")
392
+ regex="^"+regex+"$"
393
+ if (matchdata=line.match(regex))
394
+ values={"pattern" => pattern}
395
+ (1..variables.length).each do |i|
396
+ if find_regex(extract_varname(variables[i-1])).nil?
397
+ values[variables[i-1]]=Construqt::Util.expandRangeDefinition(matchdata[i])
398
+ else
399
+ values[variables[i-1]]=[matchdata[i]]
400
+ end
401
+ end
402
+ return values
403
+ end
404
+ end
405
+ return false
406
+ end
407
+
408
+ def self.compare(nu, old)
409
+ nu_ports=nu.nil? ? {} : nu.integrate
410
+ old_ports=old.nil? ? {} : old.integrate
411
+
412
+ result = self.new(self.section)
413
+
414
+ key_var = (old||nu).find_key_var
415
+ set_keys = (old||nu).keys_of_set + (nu||old).keys_of_set
416
+
417
+ set_keys.each do |key_val|
418
+ variables(self.patterns).each do |v|
419
+ if is_key_value?(v)
420
+ result.add({key_var => key_val})
421
+ elsif is_value?(v)
422
+ result.add({key_var => key_val, v => (nu_ports[key_val] && nu_ports[key_val][v]) ? nu_ports[key_val][v] : nil})
423
+ else
424
+ set = []
425
+ set += nu_ports[key_val][v] if nu_ports[key_val]
426
+ set += old_ports[key_val][invert(v)] if old_ports[key_val] && old_ports[key_val][invert(v)]
427
+ set -= nu_ports[key_val][invert(v)] if nu_ports[key_val] && nu_ports[key_val][invert(v)]
428
+ set -= old_ports[key_val][v] if old_ports[key_val]
429
+ result.add({key_var => key_val, v => set}) if set.length > 0
430
+ end
431
+ end
432
+ end
433
+
434
+ return [result]
435
+ end
436
+
437
+ def self.is_key_value?(v)
438
+ return !v.nil? && v.start_with?("{*")
439
+ end
440
+
441
+ def self.is_value?(v)
442
+ return !v.nil? && v.start_with?("{=")
443
+ end
444
+
445
+ def find_key_var
446
+ #find variable for key
447
+ key_var=nil
448
+ changes.each do |entry|
449
+ entry.keys.each do |v|
450
+ if self.class.is_key_value?(v)
451
+ throw "can only have one key value variable in pattern {*var}" if key_var !=nil && key_var !=v
452
+ key_var = v
453
+ end
454
+ end
455
+ end
456
+ return key_var
457
+ end
458
+
459
+ def keys_of_set
460
+ keys=[]
461
+
462
+ key_var=find_key_var
463
+
464
+ if key_var
465
+ changes.each do |entry|
466
+ keys << entry[key_var] if entry[key_var]
467
+ end
468
+ end
469
+
470
+ return keys unless keys.empty?
471
+ return [nil]
472
+ end
473
+
474
+ def integrate
475
+ set_keys = keys_of_set
476
+
477
+ #initialize sets
478
+ sets={}
479
+ set_keys.each do |key_val|
480
+ sets[key_val] = {}
481
+ end
482
+
483
+ #initialize start values of values inside sets
484
+ set_keys.each do |key_val|
485
+ self.class.variables(self.class.patterns).each do |v|
486
+ if self.class.is_key_value?(v)
487
+ sets[key_val][v]=key_val
488
+ elsif self.class.is_value?(v)
489
+ sets[key_val][v]=nil
490
+ else
491
+ sets[key_val][v]=[]
492
+ end
493
+ end
494
+ end
495
+
496
+ key_var=find_key_var
497
+ changes.each do |entry|
498
+ sets.each do|key_val,value_sets|
499
+ value_sets.each do |v,set|
500
+ if (entry[key_var]==key_val)
501
+ if self.class.is_key_value?(v)
502
+ value_sets[v] = entry[v]
503
+ elsif self.class.is_value?(v)
504
+ value_sets[v] = entry[v]
505
+ else
506
+ value_sets[v] += entry[v] if entry[v]
507
+ #remove duplicates without changing insertion order:
508
+ value_sets[v] = value_sets[v].reverse.uniq.reverse
509
+
510
+ value_sets[self.class.invert(v)] -= entry[v] if entry[v] && value_sets[self.class.invert(v)]
511
+ end
512
+ end
513
+ end
514
+ end
515
+ end
516
+
517
+ return sets
518
+ end
519
+
520
+ def determine_output_patterns(value_sets)
521
+ output_patterns=[]
522
+ empty_pattern = nil
523
+ self.class.patterns.each do |pattern|
524
+ pvs = self.class.find_variables(pattern)
525
+ if (pvs.empty?)
526
+ empty_pattern=pattern
527
+ else
528
+ pvs.each do |pv|
529
+ if (!value_sets[pv].nil? && !value_sets[pv].empty?)
530
+ output_patterns << pattern
531
+ break
532
+ end
533
+ end
534
+ end
535
+ end
536
+ output_patterns << empty_pattern if output_patterns.empty? && !empty_pattern.nil?
537
+ return output_patterns
538
+ end
539
+
540
+ def serialize
541
+ buffer = []
542
+ sets = integrate
543
+
544
+ # deactivate grouping, if one variable has a custom regex (i.e. is not a range definition)
545
+ group=true
546
+ self.class.variables(self.class.patterns).each do |v|
547
+ group=false unless self.class.find_regex(self.class.extract_varname(v)).nil?
548
+ end
549
+
550
+ sets.each do |key_val,value_sets|
551
+ determine_output_patterns(value_sets).each do |pattern|
552
+ index = 0
553
+ i=0
554
+ begin
555
+ substitution=false
556
+ result = pattern
557
+ i+=1
558
+ self.class.find_variables(pattern).each do |v|
559
+ if (group)
560
+ result = result.gsub(v, Construqt::Util.createRangeDefinition(value_sets[v])) unless value_sets[v].nil? || value_sets[v].empty?
561
+ else
562
+ if (index < value_sets[v].length)
563
+ result = result.gsub(v, value_sets[v][index])
564
+ substitution=true
565
+ end
566
+ end
567
+ end
568
+ buffer << result if self.class.find_variables(result).empty?
569
+ index+=1
570
+ end while substitution
571
+ end
572
+ end
573
+ return buffer
574
+ end
575
+ end
576
+
577
+ class Host < OpenStruct
578
+ def initialize(cfg)
579
+ super(cfg)
580
+ end
581
+
582
+ def header(host)
583
+ "# this is a generated file do not edit!!!!!"
584
+ end
585
+ def footer(host)
586
+ "# this is a generated file do not edit!!!!!"
587
+ end
588
+
589
+ def build_config(host, unused)
590
+ host.result.dialect.add_host(host)
591
+ end
592
+ end
593
+
594
+ class Device < OpenStruct
595
+ def initialize(cfg)
596
+ super(cfg)
597
+ end
598
+
599
+ def self.header(path)
600
+ "# this is a generated file do not edit!!!!!"
601
+ end
602
+
603
+ def build_config(host, device)
604
+ host.result.dialect.add_device(device)
605
+ end
606
+ end
607
+
608
+ class Vlan < OpenStruct
609
+ def initialize(cfg)
610
+ super(cfg)
611
+ end
612
+
613
+ def self.header(path)
614
+ "# this is a generated file do not edit!!!!!"
615
+ end
616
+
617
+ def build_config(host, device)
618
+ host.result.dialect.add_vlan(device)
619
+ end
620
+ end
621
+
622
+ class Bond < OpenStruct
623
+ def initialize(cfg)
624
+ super(cfg)
625
+ end
626
+
627
+ def self.header(path)
628
+ "# this is a generated file do not edit!!!!!"
629
+ end
630
+
631
+ def build_config(host, bond)
632
+ host.result.dialect.add_bond(bond)
633
+ end
634
+ end
635
+
636
+ class NotImplemented < OpenStruct
637
+ def initialize(cfg)
638
+ super(cfg)
639
+ end
640
+
641
+ def self.header(path)
642
+ "# this is a generated file do not edit!!!!!"
643
+ end
644
+
645
+ def build_config(host, iface)
646
+ throw "not implemented on this flavour #{iface.class.name}"
647
+ end
648
+ end
649
+
650
+ def self.clazzes
651
+ {
652
+ "opvn" => NotImplemented,
653
+ "bond" => Bond,
654
+ "bridge" => NotImplemented,
655
+ "gre" => NotImplemented,
656
+ "vrrp" => NotImplemented,
657
+ "template" => NotImplemented,
658
+ "vlan" => Vlan,
659
+ "host" => Host,
660
+ "device"=> Device,
661
+ "result" => Result
662
+ }
663
+ end
664
+
665
+ def self.clazz(name)
666
+ ret = self.clazzes[name]
667
+ throw "class not found #{name}" unless ret
668
+ ret
669
+ end
670
+
671
+ def self.create_host(name, cfg)
672
+ cfg['name'] = name
673
+ cfg['result'] = nil
674
+ host = Host.new(cfg)
675
+ host.result = Result.new(host)
676
+ host
677
+ end
678
+
679
+ def self.create_interface(name, cfg)
680
+ cfg['name'] = name
681
+ clazz(cfg['clazz']).new(cfg)
682
+ #cfg['name'] = name
683
+ #Interface.new(cfg)
684
+ end
685
+ end
686
+ end
687
+ end