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.
- checksums.yaml +7 -0
- data/lib/construqt/addresses.rb +204 -0
- data/lib/construqt/bgps.rb +164 -0
- data/lib/construqt/cables.rb +47 -0
- data/lib/construqt/firewalls.rb +247 -0
- data/lib/construqt/flavour/ciscian/ciscian.rb +687 -0
- data/lib/construqt/flavour/ciscian/dialect_dlink-dgs15xx.rb +235 -0
- data/lib/construqt/flavour/ciscian/dialect_hp-2510g.rb +114 -0
- data/lib/construqt/flavour/delegates.rb +448 -0
- data/lib/construqt/flavour/flavour.rb +97 -0
- data/lib/construqt/flavour/mikrotik/flavour_mikrotik.rb +417 -0
- data/lib/construqt/flavour/mikrotik/flavour_mikrotik_bgp.rb +134 -0
- data/lib/construqt/flavour/mikrotik/flavour_mikrotik_interface.rb +79 -0
- data/lib/construqt/flavour/mikrotik/flavour_mikrotik_ipsec.rb +65 -0
- data/lib/construqt/flavour/mikrotik/flavour_mikrotik_result.rb +182 -0
- data/lib/construqt/flavour/mikrotik/flavour_mikrotik_schema.rb +355 -0
- data/lib/construqt/flavour/plantuml/plantuml.rb +462 -0
- data/lib/construqt/flavour/ubuntu/flavour_ubuntu.rb +381 -0
- data/lib/construqt/flavour/ubuntu/flavour_ubuntu_bgp.rb +117 -0
- data/lib/construqt/flavour/ubuntu/flavour_ubuntu_dns.rb +97 -0
- data/lib/construqt/flavour/ubuntu/flavour_ubuntu_firewall.rb +300 -0
- data/lib/construqt/flavour/ubuntu/flavour_ubuntu_ipsec.rb +144 -0
- data/lib/construqt/flavour/ubuntu/flavour_ubuntu_opvn.rb +60 -0
- data/lib/construqt/flavour/ubuntu/flavour_ubuntu_result.rb +537 -0
- data/lib/construqt/flavour/ubuntu/flavour_ubuntu_services.rb +115 -0
- data/lib/construqt/flavour/ubuntu/flavour_ubuntu_vrrp.rb +52 -0
- data/lib/construqt/flavour/unknown/unknown.rb +175 -0
- data/lib/construqt/hostid.rb +42 -0
- data/lib/construqt/hosts.rb +98 -0
- data/lib/construqt/interfaces.rb +166 -0
- data/lib/construqt/ipsecs.rb +64 -0
- data/lib/construqt/networks.rb +81 -0
- data/lib/construqt/regions.rb +32 -0
- data/lib/construqt/resource.rb +42 -0
- data/lib/construqt/services.rb +53 -0
- data/lib/construqt/tags.rb +61 -0
- data/lib/construqt/templates.rb +37 -0
- data/lib/construqt/tests/test_addresses.rb +50 -0
- data/lib/construqt/tests/test_bgps.rb +24 -0
- data/lib/construqt/tests/test_hostid.rb +32 -0
- data/lib/construqt/tests/test_hosts.rb +23 -0
- data/lib/construqt/tests/test_utils.rb +76 -0
- data/lib/construqt/users.rb +19 -0
- data/lib/construqt/util.rb +163 -0
- data/lib/construqt/version.rb +3 -0
- data/lib/construqt/vlans.rb +51 -0
- data/lib/construqt.rb +92 -0
- 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
|