construqt 0.0.5 → 0.0.6

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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/lib/construqt/addresses.rb +121 -10
  3. data/lib/construqt/bgps.rb +10 -12
  4. data/lib/construqt/firewalls.rb +115 -16
  5. data/lib/construqt/flavour/ciscian/ciscian.rb +73 -93
  6. data/lib/construqt/flavour/ciscian/deploy_template.rb +36 -0
  7. data/lib/construqt/flavour/ciscian/dialect_dlink-dgs15xx.rb +62 -114
  8. data/lib/construqt/flavour/ciscian/dialect_hp-2510g.rb +74 -14
  9. data/lib/construqt/flavour/delegates.rb +9 -0
  10. data/lib/construqt/flavour/mikrotik/flavour_mikrotik.rb +0 -3
  11. data/lib/construqt/flavour/mikrotik/flavour_mikrotik_bgp.rb +12 -1
  12. data/lib/construqt/flavour/mikrotik/flavour_mikrotik_interface.rb +32 -1
  13. data/lib/construqt/flavour/mikrotik/flavour_mikrotik_result.rb +2 -0
  14. data/lib/construqt/flavour/mikrotik/flavour_mikrotik_schema.rb +3 -3
  15. data/lib/construqt/flavour/plantuml/plantuml.rb +2 -2
  16. data/lib/construqt/flavour/ubuntu/flavour_ubuntu.rb +24 -13
  17. data/lib/construqt/flavour/ubuntu/flavour_ubuntu_bgp.rb +16 -7
  18. data/lib/construqt/flavour/ubuntu/flavour_ubuntu_dns.rb +5 -5
  19. data/lib/construqt/flavour/ubuntu/flavour_ubuntu_firewall.rb +218 -67
  20. data/lib/construqt/flavour/ubuntu/flavour_ubuntu_ipsec.rb +33 -17
  21. data/lib/construqt/flavour/ubuntu/flavour_ubuntu_opvn.rb +5 -5
  22. data/lib/construqt/flavour/ubuntu/flavour_ubuntu_result.rb +77 -14
  23. data/lib/construqt/flavour/ubuntu/flavour_ubuntu_services.rb +77 -29
  24. data/lib/construqt/flavour/ubuntu/flavour_ubuntu_vrrp.rb +18 -3
  25. data/lib/construqt/interfaces.rb +25 -6
  26. data/lib/construqt/ipsecs.rb +5 -3
  27. data/lib/construqt/rack.rb +51 -0
  28. data/lib/construqt/resource.rb +25 -3
  29. data/lib/construqt/reverse.rb +1 -0
  30. data/lib/construqt/services.rb +15 -29
  31. data/lib/construqt/tags.rb +21 -15
  32. data/lib/construqt/templates.rb +17 -0
  33. data/lib/construqt/users.rb +4 -0
  34. data/lib/construqt/util.rb +1 -1
  35. data/lib/construqt/version.rb +1 -1
  36. data/lib/construqt/vlans.rb +13 -2
  37. data/lib/construqt.rb +2 -1
  38. metadata +4 -2
@@ -1,3 +1,5 @@
1
+ require_relative("deploy_template")
2
+
1
3
  module Construqt
2
4
  module Flavour
3
5
  module Ciscian
@@ -34,21 +36,6 @@ module Construqt
34
36
  @to_s = str
35
37
  @nr = nr
36
38
  end
37
-
38
- def <=>(other)
39
- a = self.to_s
40
- b = other.to_s
41
- match_a=/^(.*[^\d])(\d+)$/.match(a)||[nil,a,1]
42
- match_b=/^(.*[^\d])(\d+)$/.match(b)||[nil,b,1]
43
- #puts match_a, match_b, a, b
44
- ret = match_a[1]<=>match_b[1]
45
- ret = match_a[2].to_i<=>match_b[2].to_i if ret==0
46
- ret
47
- end
48
-
49
- # def hash
50
- # self.to_s.hash
51
- # end
52
39
  end
53
40
 
54
41
  def initialize(lines)
@@ -91,19 +78,25 @@ module Construqt
91
78
  end
92
79
  end
93
80
 
94
- def commit
95
- self.dialect.commit
96
-
81
+ def serialize
97
82
  block=[]
98
- @sections.keys.sort.each do |key|
83
+ section_keys = self.dialect.sort_section_keys(@sections.keys)
84
+ section_keys.each do |key|
99
85
  section = @sections[key]
100
86
  block += section.serialize
101
87
  end
88
+ block
89
+ end
102
90
 
103
- Util.write_str(block.join("\n"), File.join(@host.name, "#{@host.fname||self.dialect.class.name}.cfg"))
91
+ def commit
92
+ self.dialect.commit
93
+ Util.write_str(self.serialize().join("\n"), File.join(@host.name, "#{@host.fname||self.dialect.class.name}.cfg"))
94
+ external=@host.id.interfaces.first.address
95
+ external_ip=external.first_ipv4.nil? ? external.first_ipv6.to_s : external.first_ipv4.to_s
96
+ DeployTemplate.write_template(@host, self.dialect.class.name, external_ip, "root", @host.password||@host.region.hosts.default_password)
104
97
  end
105
98
 
106
- def add(section, clazz=NestedSection)
99
+ def add(section, clazz=SingleValueVerb)
107
100
  throw "section is nil" unless section
108
101
  section = Lines::Line.new(section, -1) unless section.kind_of?(Lines::Line)
109
102
  section_key=Result.normalize_section_key(section.to_s)
@@ -115,7 +108,7 @@ module Construqt
115
108
  @sections[section_key].yes
116
109
  end
117
110
 
118
- yield(@sections[section_key]) if block_given?
111
+ yield(@sections[section_key]) if block_given?
119
112
  @sections[section_key]
120
113
  end
121
114
 
@@ -129,7 +122,7 @@ module Construqt
129
122
 
130
123
  deltas=NestedSection.compare(nu_root, other_root)
131
124
  throw "illegal state" if deltas.length != 1
132
- result.sections = deltas[0]
125
+ result.sections = deltas[0].sections unless deltas[0].nil?
133
126
  result
134
127
  end
135
128
  end
@@ -141,18 +134,21 @@ module Construqt
141
134
  end
142
135
 
143
136
  def serialize
144
- [[@no, section , value].compact.join(" ")]
137
+ val = @quotes ? "\"#{value}\"" : value
138
+ [[@no, section , val].compact.join(" ")]
145
139
  end
146
140
 
147
141
  def self.compare(nu, old)
148
142
  return [nu] unless old
149
- return [old.no] unless nu
143
+ # return no changes (empty list) if old configuration of single value verb (default) is not explicitly reconfigured in new configuration:
144
+ return [] unless nu
150
145
  return [nu] unless nu.serialize == old.serialize
151
146
  [nil]
152
147
  end
153
148
 
154
149
  def add(value)
155
150
  self.value=value
151
+ self
156
152
  end
157
153
 
158
154
  def no
@@ -166,10 +162,19 @@ module Construqt
166
162
  self
167
163
  end
168
164
 
165
+ def quotes
166
+ @quotes=true
167
+ self
168
+ end
169
+
169
170
  def self.parse_line(line, lines, section, result)
170
- regexp = line.to_s.strip.end_with?("\"") ? /^(.*) (\"[^"]+\")$/ : /^(.*) ([^\s"]+)$/
171
+ quotes = line.to_s.strip.end_with?("\"")
172
+ regexp = quotes ? /^\s*((no|).*) \"([^"]+)\"$/ : /^\s*((no|).*) ([^\s"]+)$/
171
173
  if (line.to_s.strip =~ regexp)
172
- section.add($1, Ciscian::SingleValueVerb).add($2)
174
+ key=$1
175
+ val=$3
176
+ sec = section.add(key, Ciscian::SingleValueVerb).add(val)
177
+ sec.quotes if quotes
173
178
  else
174
179
  section.add(line.to_s, Ciscian::SingleValueVerb)
175
180
  end
@@ -183,20 +188,21 @@ module Construqt
183
188
  self.section=section
184
189
  end
185
190
 
186
- def add(verb, clazz = MultiValueVerb)
187
- # if verb.respond_to?(:section_key)
188
- # clazz=verb
189
- # verb=clazz.section_key
190
- # end
191
+ def add(verb, clazz = SingleValueVerb)
192
+ section_key=Result.normalize_section_key(verb.to_s)
193
+ self.sections[section_key] ||= clazz.new(section_key)
191
194
 
192
- self.sections[Result.normalize_section_key(verb.to_s)] ||= clazz.new(verb)
195
+ if Result.starts_with_no(verb.to_s)
196
+ @sections[section_key].no
197
+ end
198
+ @sections[section_key]
193
199
  end
194
200
 
195
201
  def self.parse_line(line, lines, section, result)
196
- #binding.pry if line.start_with?("interface")
197
202
  if [/^\s*(no\s+|)interface/, /^\s*(no\s+|)vlan/].find{|i| line.to_s.match(i) }
198
203
  resultline=Result::Lines::Line.new(result.dialect.clear_interface(line), line.nr)
199
- section.add(resultline.to_s) do |_section|
204
+ section.add(resultline.to_s, NestedSection) do |_section|
205
+ _section.virtual if result.dialect.is_virtual?(resultline.to_s)
200
206
  while _line = lines.shift
201
207
  break if result.dialect.block_end?(_line.to_s)
202
208
  result.parse_line(_line, lines, _section, result)
@@ -208,7 +214,7 @@ module Construqt
208
214
  if (ports.length>1)
209
215
  section_to_split=section.sections.delete(resultline.to_s)
210
216
  ports.each do |port|
211
- section.add(line.to_s.gsub(/#{Construqt::Util::PORTS_DEF_REGEXP}/, port)) do |_section|
217
+ section.add(line.to_s.gsub(/#{Construqt::Util::PORTS_DEF_REGEXP}/, port), NestedSection) do |_section|
212
218
  _section.sections.merge!(section_to_split.sections)
213
219
  end
214
220
  end
@@ -244,12 +250,19 @@ module Construqt
244
250
  self
245
251
  end
246
252
 
253
+ def virtual
254
+ @virtual=true
255
+ self
256
+ end
257
+
247
258
  def serialize
248
259
  block=[]
249
- block << "#{@no}#{section.to_s}"
250
- unless (@no)
251
- block += render_verbs(self.sections)
252
- block << "exit"
260
+ if (!self.sections.empty? || (self.sections.empty? && @virtual) || (@no && @virtual))
261
+ block << "#{@no}#{section.to_s}"
262
+ unless (@no)
263
+ block += render_verbs(self.sections)
264
+ block << "exit"
265
+ end
253
266
  end
254
267
 
255
268
  block
@@ -259,6 +272,7 @@ module Construqt
259
272
  return [nu] unless old
260
273
  return [old.no] unless nu
261
274
  throw "classes must match #{nu.class.name} != #{old.class.name}" unless nu.class == old.class
275
+
262
276
  if (nu.serialize==old.serialize)
263
277
  return [nil]
264
278
  else
@@ -266,7 +280,7 @@ module Construqt
266
280
  return [nu]
267
281
  else
268
282
  delta = nu.class.new(nu.section)
269
- (nu.sections.keys + old.sections.keys).sort.each do |k,v|
283
+ (nu.sections.keys + old.sections.keys).uniq.sort.each do |k,v|
270
284
  nu_section=nu.sections[k]
271
285
  old_section=old.sections[k]
272
286
  comps = (nu_section||old_section).class.compare(nu_section, old_section)
@@ -282,48 +296,6 @@ module Construqt
282
296
  end
283
297
  end
284
298
 
285
- class MultiValueVerb
286
- attr_accessor :section,:values
287
- def initialize(section)
288
- self.section=section
289
- self.values = []
290
- end
291
-
292
- def add(value)
293
- self.values << value
294
- self
295
- end
296
-
297
- def no
298
- @no="no "
299
- self
300
- end
301
-
302
- def yes
303
- @no=nil
304
- self
305
- end
306
-
307
- def serialize
308
- if @no
309
- ["#{@no}#{section}"]
310
- else
311
- ["#{section} #{values.join(",")}"]
312
- end
313
- end
314
-
315
- def self.compare(nu, old)
316
- return [nu] unless old
317
- return [old.no] unless nu
318
- throw "classes must match #{nu.class.name} != #{old.class.name}" unless nu.class == old.class
319
- if (nu.serialize==old.serialize)
320
- [nil]
321
- else
322
- [nu]
323
- end
324
- end
325
- end
326
-
327
299
  class RangeVerb
328
300
  attr_accessor :section,:values
329
301
  def initialize(section)
@@ -360,7 +332,7 @@ module Construqt
360
332
 
361
333
  def serialize
362
334
  if @no
363
- ["#{@no}#{section}"]
335
+ ["#{@no}#{section} #{Construqt::Util.createRangeDefinition(values)}"]
364
336
  else
365
337
  ["#{section} #{Construqt::Util.createRangeDefinition(values)}"]
366
338
  end
@@ -449,6 +421,12 @@ module Construqt
449
421
  end
450
422
 
451
423
  def self.compare(nu, old)
424
+ unless (nu.nil? || old.nil?)
425
+ if (nu.serialize==old.serialize)
426
+ return []
427
+ end
428
+ end
429
+
452
430
  nu_ports=nu.nil? ? {} : nu.integrate
453
431
  old_ports=old.nil? ? {} : old.integrate
454
432
 
@@ -561,6 +539,10 @@ module Construqt
561
539
  return sets
562
540
  end
563
541
 
542
+ def always_select_empty_pattern
543
+ false
544
+ end
545
+
564
546
  def determine_output_patterns(value_sets)
565
547
  output_patterns=[]
566
548
  empty_pattern = nil
@@ -578,20 +560,18 @@ module Construqt
578
560
  end
579
561
  end
580
562
 
581
- output_patterns << empty_pattern if output_patterns.empty? && !empty_pattern.nil?
563
+ output_patterns.unshift(empty_pattern) if (output_patterns.empty? || self.always_select_empty_pattern) && !empty_pattern.nil?
582
564
  return output_patterns
583
565
  end
584
566
 
567
+ def group?
568
+ true
569
+ end
570
+
585
571
  def serialize
586
572
  buffer = []
587
573
  sets = integrate
588
574
 
589
- # deactivate grouping, if one variable has a custom regex (i.e. is not a range definition)
590
- group=true
591
- self.class.variables(self.class.patterns).each do |v|
592
- group=false unless self.class.find_regex(self.class.extract_varname(v)).nil?
593
- end
594
-
595
575
  sets.each do |key_val,value_sets|
596
576
  determine_output_patterns(value_sets).each do |pattern|
597
577
  index = 0
@@ -601,8 +581,8 @@ module Construqt
601
581
  result = pattern
602
582
  i += 1
603
583
  self.class.find_variables(pattern).each do |v|
604
- if (group)
605
- if self.class.is_value?(v) || self.class.is_key_value?(v)
584
+ if (self.group?)
585
+ if (!value_sets[v].kind_of?(Array) && (self.class.is_value?(v) || self.class.is_key_value?(v)))
606
586
  result = result.gsub(v, value_sets[v].to_s) unless value_sets[v].nil? || value_sets[v].to_s.empty?
607
587
  else
608
588
  result = result.gsub(v, Construqt::Util.createRangeDefinition(value_sets[v])) unless value_sets[v].nil? || value_sets[v].empty?
@@ -0,0 +1,36 @@
1
+ module Construqt
2
+ module Flavour
3
+ module Ciscian
4
+ class DeployTemplate
5
+ def self.write_template(host, flavour, ip, user, pass)
6
+ template = <<-TEMPLATE
7
+ #!/bin/bash
8
+
9
+ CURRENT_DIR="`pwd`/$(dirname $0)"
10
+ if [[ ! -e $CURRENT_DIR ]]
11
+ then
12
+ CURRENT_DIR="$(dirname $0)"
13
+ fi
14
+
15
+ if [ -z "$CONSTRUQT_PATH" ]
16
+ then
17
+ if [[ $CURRENT_DIR =~ (.*construqt).* ]]
18
+ then
19
+ CONSTRUQT_PATH=${BASH_REMATCH[1]}
20
+ else
21
+ echo "could not automatically find construqt path"
22
+ exit
23
+ fi
24
+ fi
25
+
26
+ FLAVOUR="#{flavour}"
27
+ cd $CONSTRUQT_PATH
28
+ bash $CONSTRUQT_PATH/construqt/switch/deploy/deploy.sh $FLAVOUR #{ip} #{user} #{pass} "$CURRENT_DIR/$FLAVOUR.cfg"
29
+ cd - > /dev/null
30
+ TEMPLATE
31
+ Util.write_str(template, File.join(host.name, "deploy.sh"))
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -52,6 +52,10 @@ module Construqt
52
52
  "channel-group"
53
53
  end
54
54
 
55
+ def always_select_empty_pattern
56
+ true
57
+ end
58
+
55
59
  def self.patterns
56
60
  ["no channel-group", "channel-group {+channel} mode active"]
57
61
  end
@@ -94,12 +98,15 @@ module Construqt
94
98
  end
95
99
  end
96
100
 
97
-
98
101
  class Ipv4RouteVerb < PatternBasedVerb
99
102
  def self.section
100
103
  "ip route"
101
104
  end
102
105
 
106
+ def group?
107
+ false
108
+ end
109
+
103
110
  def self.find_regex(variable)
104
111
  {
105
112
  "routedefs" => "(\\S+\\s+\\S+\\s+\\S+)"
@@ -111,6 +118,16 @@ module Construqt
111
118
  end
112
119
  end
113
120
 
121
+ class IpHttpServerVerb < SingleValueVerb
122
+ def self.parse_line(line, lines, section, result)
123
+ regexp = /^\s*((no|) ip http server)$/
124
+ if (line.to_s.strip =~ regexp)
125
+ section.add(line.to_s, Ciscian::SingleValueVerb)
126
+ return true
127
+ end
128
+ end
129
+ end
130
+
114
131
  class Comment
115
132
  def self.parse_line(line, lines, section, result)
116
133
  line.to_s.empty? || line.to_s.start_with?("#")
@@ -126,7 +143,7 @@ module Construqt
126
143
  class Line
127
144
  def self.parse_line(line, lines, section, result)
128
145
  return false unless ['line '].find{|i| line.to_s.start_with?(i) }
129
- section.add(line) do |_section|
146
+ section.add(line, NestedSection) do |_section|
130
147
  while line = lines.shift
131
148
  break if result.dialect.block_end?(line.to_s)
132
149
  result.parse_line(line, lines, _section, result)
@@ -163,15 +180,6 @@ module Construqt
163
180
  def add_host(host)
164
181
  end
165
182
 
166
- def add_device(device)
167
- @result.add("interface #{expand_device_name(device)}") do |section|
168
- section.add("flowcontrol").add("off")
169
- section.add("max-rcv-frame-size").add(device.delegate.mtu)
170
- section.add("snmp trap").add("link-status")
171
- section.add("switchport mode").add("trunk")
172
- end
173
- end
174
-
175
183
  def clear_interface(line)
176
184
  line.to_s.split(/\s+/).map do |i|
177
185
  split = /^([^0-9]+)([0-9].*)$/.match(i)
@@ -179,6 +187,10 @@ module Construqt
179
187
  end.flatten.join(' ')
180
188
  end
181
189
 
190
+ def is_virtual?(line)
191
+ line.start_with?("vlan") || line.include?("port-channel")
192
+ end
193
+
182
194
  def parse_line(line, lines, section, result)
183
195
  [
184
196
  WtfEnd,
@@ -189,12 +201,34 @@ module Construqt
189
201
  MtuVerb,
190
202
  SwitchPortTrunkAllowedVlan,
191
203
  ChannelGroupVerb,
192
- Ipv4RouteVerb
204
+ Ipv4RouteVerb,
205
+ IpHttpServerVerb
193
206
  ].find do |i|
194
207
  i.parse_line(line, lines, section, result)
195
208
  end
196
209
  end
197
210
 
211
+ def sort_section_keys(keys)
212
+ return keys.sort do |a,b|
213
+ a = a.to_s
214
+ b = b.to_s
215
+ match_a=/^(.*[^\d])(\d+)$/.match(a)||[nil,a,1]
216
+ match_b=/^(.*[^\d])(\d+)$/.match(b)||[nil,b,1]
217
+ #puts match_a, match_b, a, b
218
+ ret=0
219
+ ret = rate_higher("vlan", match_a[1], match_b[1]) if ret==0
220
+ ret = rate_higher("interface port-channel", match_a[1], match_b[1]) if ret==0
221
+ ret = rate_higher("interface vlan", match_a[1], match_b[1]) if ret==0
222
+ ret = match_a[1]<=>match_b[1] if ret==0
223
+ ret = match_a[2].to_i<=>match_b[2].to_i if ret==0
224
+ ret
225
+ end
226
+ end
227
+
228
+ def rate_higher(prefix, a, b)
229
+ return a.start_with?(prefix) ^ b.start_with?(prefix) ? (a.start_with?(prefix) ? -1 : 1) : 0
230
+ end
231
+
198
232
  def expand_device_name(device)
199
233
  return device.delegate.dev_name if device.delegate.dev_name
200
234
  pattern = (({
@@ -217,137 +251,51 @@ module Construqt
217
251
  @result.add(verb, Ciscian::SingleValueVerb)
218
252
  end
219
253
 
220
- ["line console", "line telnet", "line ssh"].each do |section|
221
- @result.add(section) { |_section| _section.add("line") }
222
- end
223
-
224
- #@result.host.interfaces.values.each do |iface|
225
- # @result.add(k
226
- #end
227
-
228
-
229
-
230
-
231
- # "enable password level 15 7 <>"
232
- # "username root password 7 <>"
233
- # "username root password 15"
234
- #
235
- # "autoconfig",
236
- # ["clock timezone", "+ 1"],
237
- # "no clock summer-time"
238
- # "sntp interval 720"
239
- # "ddp report-timer 30",
240
- # "debug"
241
- # "debug reboot"
242
- # "dim"
243
- # "ignore"
244
- # "instance 16 vlans"
245
- # no power-saving link-detection
246
- # no dim led
247
- # no power-saving hibernation
248
- # no power-saving dim-led
249
- # no power-saving port-shutdown
250
- #
251
- #
252
- # "ddp"
253
- # "no power-saving eee"
254
- # "no snmp-server trap-sending"
255
- # "no speed"
256
- # "spanning-tree guard"
257
- # "spanning-tree mst hello-time"
258
- #
259
- #
260
- # "ip arp gratuitous"
261
- # "ip dhcp relay information option format circuit-id default"
262
- # "ip dhcp relay information option format remote-id default"
263
- # "ip dhcp relay information policy replace"
264
- # "ip domain"
265
- # "ip http service-port"
266
- # "ip http timeout-policy idle"
267
- # "ip ssh"
268
- # "ip telnet"
269
- # "ip telnet service-port"
270
- # "port-channel load-balance"
271
- # "power-saving"
272
- # "service"
273
- #
274
- # "snmp-server community private view CommunityView"
275
- # "snmp-server community public view CommunityView"
276
- # "snmp-server contact"
277
- # "snmp-server enable traps rmon falling-alarm"
278
- # "snmp-server enable traps snmp rising-alarm"
279
- # "snmp-server engineID local"
280
- # "snmp-server group initial"
281
- # "snmp-server group initial v3 noauth read restricted notify"
282
- # "snmp-server group private v1 read CommunityView write CommunityView notify"
283
- # "snmp-server group private v2c read CommunityView write CommunityView notify"
284
- # "snmp-server group public v1 read CommunityView notify"
285
- # "snmp-server group public v2c read CommunityView notify"
286
- # "snmp-server location"
287
- # "snmp-server response"
288
- # "snmp-server service-port"
289
- # "snmp-server user initial"
290
- # "snmp-server user initial initial"
291
- # "snmp-server view CommunityView 1"
292
- # "snmp-server view CommunityView 1.3.6.1.6.3"
293
- # "snmp-server view CommunityView 1.3.6.1.6.3.1"
294
- # "snmp-server view restricted 1.3.6.1.2.1.1"
295
- # "snmp-server view restricted 1.3.6.1.2.1.11"
296
- # "snmp-server view restricted 1.3.6.1.6.3.10.2.1"
297
- # "snmp-server view restricted 1.3.6.1.6.3.11.2.1"
298
- # "snmp-server view restricted 1.3.6.1.6.3.15.1.1"
299
- # "sntp"
300
- # "sntp interval"
301
- # "spanning-tree mode"
302
- # "spanning-tree mst"
303
- # "ssh user root authentication-method"
304
- # "username root password 7"
305
- # "username root privilege"
306
- #
307
-
308
-
309
- @result.add("snmp-server name", Ciscian::SingleValueVerb).add(@result.host.name)
254
+ @result.add("snmp-server name").add(@result.host.name)
310
255
  @result.host.interfaces.values.each do |iface|
311
256
  next unless iface.delegate.address
312
257
  iface.delegate.address.routes.each do |route|
313
258
  ip = route.dst.ipv6? ? "ipv6" : "ip"
314
- @result.add("#{ip} route #{route.dst.to_string} vlan#{iface.delegate.vlan_id} #{route.via.to_s}", Ciscian::SingleValueVerb)
259
+ @result.add("#{ip} route #{route.dst.to_string.upcase} vlan#{iface.delegate.vlan_id} #{route.via.to_s.upcase}", Ciscian::SingleValueVerb)
315
260
  end
316
261
  end
317
262
  end
318
263
 
319
- def add_device(device)
320
- @result.add("interface #{expand_device_name(device)}") do |section|
321
- section.add("flowcontrol").add("off")
322
- section.add("max-rcv-frame-size").add(device.delegate.mtu)
323
- section.add("snmp trap").add("link-status")
264
+ def add_device(device, bond=false)
265
+ @result.add("interface #{expand_device_name(device)}", NestedSection) do |section|
324
266
  section.add("switchport mode").add("trunk")
267
+ unless bond
268
+ section.add("flowcontrol").add("off")
269
+ section.add("max-rcv-frame-size").add(device.delegate.mtu)
270
+ section.add("snmp trap").add("link-status")
271
+ end
325
272
  end
326
273
  end
327
274
 
328
275
  def add_bond(bond)
329
276
  bond.interfaces.each do |iface|
330
- @result.add("interface #{expand_device_name(iface)}") do |section|
277
+ @result.add("interface #{expand_device_name(iface)}", NestedSection) do |section|
331
278
  section.add("channel-group", ChannelGroupVerb).add({"{+channel}" => [bond.name[2..-1]]})
332
279
  end
333
280
  end
281
+ self.add_device(bond, true)
334
282
  end
335
283
 
336
284
  def add_vlan(vlan)
337
- @result.add("vlan #{vlan.delegate.vlan_id}") do |section|
285
+ @result.add("vlan #{vlan.delegate.vlan_id}", NestedSection) do |section|
338
286
  next unless vlan.delegate.description && !vlan.delegate.description.empty?
339
287
  throw "vlan name too long, max 32 chars" if vlan.delegate.description.length > 32
340
288
  section.add("name").add(vlan.delegate.description)
341
289
  end
342
- @result.add("interface vlan #{vlan.delegate.vlan_id}") do |section|
290
+ @result.add("interface vlan #{vlan.delegate.vlan_id}", NestedSection) do |section|
343
291
  if vlan.delegate.address
344
292
  if vlan.delegate.address.first_ipv4
345
- section.add("ip address").add(vlan.delegate.address.first_ipv4.to_string)
293
+ section.add("ip address").add(vlan.delegate.address.first_ipv4.to_string.upcase)
346
294
  elsif vlan.delegate.address.dhcpv4?
347
295
  section.add("ip address").add("dhcp-bootp")
348
296
  end
349
297
  if vlan.delegate.address.first_ipv6
350
- section.add("ipv6 address").add(vlan.delegate.address.first_ipv6.to_string)
298
+ section.add("ipv6 address").add(vlan.delegate.address.first_ipv6.to_string.upcase)
351
299
  elsif vlan.delegate.address.dhcpv6?
352
300
  section.add("ipv6 address").add("dhcp-bootp")
353
301
  end
@@ -356,7 +304,7 @@ module Construqt
356
304
 
357
305
  vlan_id=vlan.delegate.vlan_id
358
306
  vlan.interfaces.each do |iface|
359
- @result.add("interface #{expand_device_name(iface)}") do |section|
307
+ @result.add("interface #{expand_device_name(iface)}", NestedSection) do |section|
360
308
  section.add("switchport trunk allowed vlan", Ciscian::RangeVerb).add(vlan_id)
361
309
  unless iface.template.is_tagged?(vlan_id)
362
310
  section.add("switchport trunk native vlan").add(vlan_id)