construqt 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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