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,65 @@
1
+
2
+ module Construqt
3
+ module Flavour
4
+ module Mikrotik
5
+ class Ipsec < OpenStruct
6
+ def initialize(cfg)
7
+ super(cfg)
8
+ end
9
+
10
+ def set_ip_ipsec_peer(cfg)
11
+ default = {
12
+ "address" => Schema.network.required.key,
13
+ "secret" => Schema.string.required,
14
+ "local-address" => Schema.required.address,
15
+ "passive" => Schema.boolean.default(false),
16
+ "port" => Schema.int.default(500),
17
+ "auth-method" => Schema.identifier.default("pre-shared-key"),
18
+ "generate-policy" => Schema.identifier.default("no"),
19
+ # "policy-group" => Schema.identifier.default("default"),
20
+ "exchange-mode" => Schema.identifier.default("main"),
21
+ "send-initial-contact" => Schema.boolean.default(true),
22
+ "nat-traversal" => Schema.boolean.default(true),
23
+ "proposal-check" => Schema.identifier.default("obey"),
24
+ "hash-algorithm" => Schema.identifier.default("sha1"),
25
+ "enc-algorithm" => Schema.identifier.default("aes-256"),
26
+ "dh-group" => Schema.identifier.default("modp1536"),
27
+ "lifetime" => Schema.interval.default("1d00:00:00"),
28
+ "lifebytes" => Schema.int.default(0),
29
+ "dpd-interval" => Schema.identifier.default("2m"),
30
+ "dpd-maximum-failures" => Schema.int.default(5)
31
+ }
32
+ self.host.result.render_mikrotik(default, cfg, "ip", "ipsec", "peer")
33
+ end
34
+
35
+ def set_ip_ipsec_policy(cfg)
36
+ default = {
37
+ "sa-src-address" => Schema.address.required.key,
38
+ "sa-dst-address" => Schema.address.required.key,
39
+ "src-address" => Schema.network.required,
40
+ "dst-address" => Schema.network.required,
41
+ "src-port" => Schema.port.default("any"),
42
+ "dst-port" => Schema.port.default("any"),
43
+ "protocol" => Schema.identifier.default("all"),
44
+ "action" => Schema.identifier.default("encrypt"),
45
+ "level" => Schema.identifier.default("require"),
46
+ "ipsec-protocols" => Schema.identifier.default("esp"),
47
+ "tunnel" => Schema.boolean.default(true),
48
+ "proposal" => Schema.identifier.default("s2b-proposal"),
49
+ "priority" => Schema.int.default(0)
50
+ }
51
+ #puts "#{cfg['sa-src-address'].class.name}=>#{cfg['sa-dst-address'].class.name} #{cfg['src-address'].class.name}=>#{cfg['dst-address'].class.name} #{cfg.keys}"
52
+ self.host.result.render_mikrotik(default, cfg, "ip", "ipsec", "policy")
53
+ end
54
+
55
+ def build_config(unused, unused2)
56
+ set_ip_ipsec_peer("address" => IPAddress.parse("#{self.other.remote.first_ipv6.to_s}/128"),
57
+ "local-address" => self.remote.first_ipv6,
58
+ "secret" => Util.password(self.cfg.password))
59
+ set_ip_ipsec_policy("src-address" => self.my.first_ipv6, "sa-src-address" => self.remote.first_ipv6,
60
+ "dst-address" => self.other.my.first_ipv6, "sa-dst-address" => self.other.remote.first_ipv6)
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,182 @@
1
+ module Construqt
2
+ module Flavour
3
+ module Mikrotik
4
+ class Result
5
+ def initialize(host)
6
+ @remove_pre_condition = {}
7
+ @host = host
8
+ @result = {}
9
+ end
10
+
11
+ def host
12
+ @host
13
+ end
14
+
15
+ def empty?(name)
16
+ not @result[name]
17
+ end
18
+
19
+ def prepare(default, cfg, enable = true)
20
+ if enable
21
+ default['disabled'] = Schema.boolean.default(false)
22
+ end
23
+
24
+ result = {}
25
+ cfg.each do |key, val|
26
+ unless default[key]
27
+ Construqt.logger.debug("skip cfg unknown key:#{key} val:#{val}")
28
+ else
29
+ result[key] = val
30
+ end
31
+ end
32
+
33
+ keys = {}
34
+ default.each do |key, val|
35
+ if val.kind_of?(Schema)
36
+ val.field_name = key
37
+ throw "type must set of #{key}" unless val.type?
38
+ throw "required key:#{key} not set" if val.required? and (result[key].nil? or result[key].to_s.empty?)
39
+ result[key] = val.get_default if !val.get_default.nil? && result[key].nil?
40
+ keys[key] = result[key] if val.key?
41
+ else
42
+ throw "default type has to be a schema #{val}"
43
+ end
44
+ end
45
+
46
+ OpenStruct.new(
47
+ :key => keys.map{|k,v| "#{k}=#{default[k].serialize(v)}"}.sort.join(" && "),
48
+ :result => result,
49
+ :add_line => result.select{ |k,v|
50
+ if default[k].kind_of?(Schema) && default[k].noset?
51
+ false
52
+ else
53
+ !(v.to_s.empty?)
54
+ end
55
+
56
+ }.map{|k,v| "#{k}=#{default[k].serialize(v)}"}.sort.join(" ")
57
+ )
58
+ end
59
+
60
+ def render_mikrotik_set_direct(default, cfg, *path)
61
+ prepared = prepare(default, cfg, false)
62
+ add("set #{prepared.add_line}", nil, *path)
63
+ end
64
+
65
+ def render_mikrotik_set_by_key(default, cfg, *path)
66
+ prepared = prepare(default, cfg)
67
+ add("set [ find #{prepared.key} ] #{prepared.add_line}", nil, *path)
68
+ end
69
+
70
+ def render_mikrotik(default, cfg, *path)
71
+ enable = !cfg['no_auto_disable'] # HACK
72
+ cfg.delete("no_auto_disable")
73
+ prepared = prepare(default, cfg, enable)
74
+ ret = ["{"]
75
+ ret << " :local found [find "+prepared.key+"]"
76
+ ret << " :if ($found = \"\") do={"
77
+ ret << " :put "+"/#{path.join(' ')} add #{prepared.add_line}".inspect
78
+ ret << " add #{prepared.add_line}"
79
+ ret << " } else={"
80
+ #ret << " :put "+"/#{path.join(' ')} set #{prepared.add_line}".inspect
81
+ ret << " :local record [get $found]"
82
+ prepared.result.keys.sort.each do |key|
83
+ next if prepared.result[key].nil?
84
+ val = default[key].serialize(prepared.result[key])
85
+ next if val.to_s.empty?
86
+ compare_val = default[key].serialize_compare(prepared.result[key])
87
+ if compare_val
88
+ ret << " :if (($record->#{key.inspect})!=#{compare_val}) do={"
89
+ ret << " :put "+"/#{path.join(' ')} set [find #{prepared.key} ] #{key}=#{val}".inspect
90
+ ret << " set $found #{key}=#{val}"
91
+ ret << " }"
92
+ else
93
+ ret << " set $found #{key}=#{val}"
94
+ end
95
+ end
96
+
97
+ ret << " }"
98
+ ret << "}"
99
+ add(ret.join("\n"), prepared.key, *path)
100
+ end
101
+
102
+ def add(block, digest, *path)
103
+ key = File.join(*path)
104
+ @result[key] ||= []
105
+ @result[key] << OpenStruct.new(:digest => digest, :block => block, :path => path)
106
+ @result[key]
107
+ end
108
+
109
+ def add_remove_pre_condition(condition, *path)
110
+ @remove_pre_condition[path.join(' ')] = condition
111
+ end
112
+
113
+ def remove_condition(digests, key)
114
+ condition = @remove_pre_condition[key]
115
+ if condition
116
+ condition = "(#{condition})"
117
+ end
118
+
119
+ if digests.nil? || digests.compact.empty?
120
+ digest = nil
121
+ else
122
+ digest = "(!(#{digests.map{|i| "(#{i.digest})"}.join(" || ")}))"
123
+ end
124
+
125
+ term = [condition, digest].compact.join(" && ")
126
+ term.empty? ? "" : "remove [ find #{term} ]"
127
+ end
128
+
129
+ def commit
130
+ sorted = {}
131
+ @result.map do |path, blocks|
132
+ key = blocks.first.path.join(' ')
133
+ digests = blocks.select{|i| i.digest }
134
+
135
+ sorted[key] = Util.write_str([
136
+ "/#{key}",
137
+ blocks.map{|i|i.block}.join("\n"),
138
+ remove_condition(digests, key),
139
+ ""
140
+ ].join("\n"), File.join(@host.name, "#{path}.rsc"))
141
+ end
142
+
143
+ all=[
144
+ "system identity",
145
+ "system clock",
146
+ "system script",
147
+ "system scheduler",
148
+ "user",
149
+ "interface",
150
+ "interface bonding",
151
+ "interface bridge",
152
+ "interface bridge port",
153
+ "interface vlan",
154
+ "interface vrrp",
155
+ "interface gre6",
156
+ "ipv6 address",
157
+ "ipv6 route",
158
+ "ip address",
159
+ "ip dns",
160
+ "ip route",
161
+ "ip ipsec proposal",
162
+ "ip ipsec peer",
163
+ "ip ipsec policy",
164
+ "routing filter",
165
+ "routing bgp instance",
166
+ "routing bgp peer",
167
+ "tool graphing interface",
168
+ "ip service"
169
+ ].map do |path|
170
+ if sorted[path]
171
+ sorted[path]
172
+ else
173
+ Construqt.logger.warn "WARNING [#{path}] not found #{sorted.keys.join('-')}" unless sorted[path]
174
+ ""
175
+ end
176
+ end.join("\n")
177
+ Util.write_str(all, File.join(@host.name, "all.rsc"))
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,355 @@
1
+ module Construqt
2
+ module Flavour
3
+ module Mikrotik
4
+
5
+ class Schema
6
+ module Int
7
+ def self.serialize_compare(schema, val)
8
+ self.serialize(schema, val)
9
+ end
10
+
11
+ def self.serialize(schema, val)
12
+ return val if val.nil?
13
+ throw "only 0-9 are allowed [#{val}]" unless val.to_s.match(/^[0-9]+$/)
14
+ return val.to_i
15
+ end
16
+ end
17
+
18
+ module Boolean
19
+ def self.serialize_compare(schema, val)
20
+ throw "illegal type #{val.class.name}" unless val.kind_of?(TrueClass) || val.kind_of?(FalseClass)
21
+ val ? 'true' : 'false'
22
+ end
23
+
24
+ def self.serialize(schema, val)
25
+ throw "illegal type #{val.class.name}:#{schema.field_name}" unless val.kind_of?(TrueClass) || val.kind_of?(FalseClass)
26
+ val ? 'yes' : 'no'
27
+ end
28
+ end
29
+
30
+ module String
31
+ def self.serialize_compare(schema, val)
32
+ self.serialize(schema, val)
33
+ end
34
+
35
+ def self.serialize(schema, val)
36
+ return nil if val.nil? && schema.null?
37
+ return '""' if val.nil? || val.strip.empty?
38
+ return val.strip.to_s.inspect.gsub('$', '\\$')
39
+ end
40
+ end
41
+
42
+ module Source
43
+ def self.serialize_compare(schema, val)
44
+ nil
45
+ end
46
+
47
+ def self.serialize(schema, val)
48
+ return nil if val.nil? && schema.null?
49
+ return '""' if val.nil? || val.strip.empty?
50
+ return "{\n" + val.strip.to_s + "\n}\n"
51
+ end
52
+ end
53
+
54
+ module Interval
55
+ def self.serialize_compare(schema, val)
56
+ self.serialize(schema, val)
57
+ end
58
+
59
+ def self.serialize(schema, val)
60
+ throw "not in interval format hh:mm:ss" unless /^(\dd)*\d{1,2}:\d{2}:\d{2}$/.match(val)
61
+ return val
62
+ end
63
+ end
64
+
65
+ module Identifier
66
+ def self.serialize_compare(schema, val)
67
+ self.serialize(schema, val).inspect
68
+ end
69
+
70
+ def self.serialize(schema, val)
71
+ throw "only a-zA-Z0-9_- are allowed [#{val}]" unless val.match(/^[a-zA-Z0-9\-_]+$/)
72
+ return val.to_s
73
+ end
74
+ end
75
+
76
+ module Port
77
+ def self.serialize_compare(schema, val)
78
+ self.serialize(schema, val)
79
+ end
80
+
81
+ def self.serialize(schema, val)
82
+ val = '0' if val == 'any'
83
+ throw "only 0-9 are allowed [#{val}]" unless val.match(/^([Z0-9]+)$/)
84
+ return val.to_s
85
+ end
86
+ end
87
+
88
+ module Identifiers
89
+ def self.serialize_compare(schema, val)
90
+ self.serialize(schema, val, ';')
91
+ end
92
+
93
+ def self.serialize(schema, val, joiner=',')
94
+ '"'+val.split(',').map{|i| Identifier.serialize(schema, i) }.join(joiner).to_s+'"'
95
+ end
96
+ end
97
+
98
+ module Address
99
+ def self.serialize_compare(schema, val)
100
+ self.serialize(schema, val).inspect
101
+ end
102
+
103
+ def self.serialize(schema, val)
104
+ throw "Address:val must be ipaddress #{val.class.name} #{val} #{schema.field_name}" unless val.kind_of?(IPAddress::IPv6) || val.kind_of?(IPAddress::IPv4)
105
+ # throw "only 0-9:\.\/ are allowed #{val}" unless val.match(/^[a-fA-F0-9:\.\/]+$/)
106
+ return Flavour::Mikrotik.compress_address(val)
107
+ end
108
+ end
109
+
110
+ module AddrPrefix
111
+ def self.serialize_compare(schema, val)
112
+ self.serialize(schema, val).inspect
113
+ end
114
+
115
+ def self.serialize(schema, val)
116
+ throw "Address:val must be ipaddress #{val.class.name} #{val} #{schema.field_name}" unless val.kind_of?(IPAddress::IPv6) || val.kind_of?(IPAddress::IPv4)
117
+ # throw "only 0-9:\.\/ are allowed #{val}" unless val.match(/^[a-fA-F0-9:\.\/]+$/)
118
+ return "#{Flavour::Mikrotik.compress_address(val)}/#{val.prefix}"
119
+ end
120
+ end
121
+
122
+ module Network
123
+ def self.serialize_compare(schema, val)
124
+ self.serialize(schema, val.network).inspect
125
+ end
126
+
127
+ def self.serialize(schema, val)
128
+ throw "Network::val must be ipaddress #{val.class.name} #{val} #{schema.field_name}" unless val.kind_of?(IPAddress::IPv6) || val.kind_of?(IPAddress::IPv4)
129
+ #throw "only 0-9:\.\/ are allowed #{val}" unless val.match(/^[a-fA-F0-9:\.\/]+$/)
130
+ return "#{Flavour::Mikrotik.compress_address(val)}/#{val.prefix}"
131
+ end
132
+ end
133
+
134
+ module Addresses
135
+ def self.serialize_compare(schema, val)
136
+ self.serialize(schema, val)
137
+ end
138
+
139
+ def self.serialize(schema, val)
140
+ val.map{|i| Address.serialize(schema, i) }.join(',').to_s
141
+ end
142
+ end
143
+
144
+ def initialize
145
+ @required = false
146
+ @key = false
147
+ @noset = false
148
+ @type = nil
149
+ @default = nil
150
+ @null = false
151
+ @field_name = nil
152
+ end
153
+
154
+ def field_name=(a)
155
+ @field_name=a
156
+ end
157
+
158
+ def field_name
159
+ @field_name
160
+ end
161
+
162
+ def serialize_compare(val)
163
+ @type.serialize_compare(self, val)
164
+ end
165
+
166
+ def serialize(val)
167
+ @type.serialize(self, val)
168
+ end
169
+
170
+ def null?
171
+ @null
172
+ end
173
+
174
+ def type?
175
+ !@type.nil?
176
+ end
177
+
178
+ def null
179
+ @null = true
180
+ self
181
+ end
182
+
183
+ def required
184
+ @required = true
185
+ self
186
+ end
187
+
188
+ def required?
189
+ @required
190
+ end
191
+
192
+ def key
193
+ @key = true
194
+ self
195
+ end
196
+
197
+ def key?
198
+ @key
199
+ end
200
+
201
+ def noset
202
+ @noset = true
203
+ self
204
+ end
205
+
206
+ def noset?
207
+ @noset
208
+ end
209
+
210
+ def int
211
+ @type = Int
212
+ self
213
+ end
214
+
215
+ def boolean
216
+ @type = Boolean
217
+ self
218
+ end
219
+
220
+ def string
221
+ @type = String
222
+ self
223
+ end
224
+
225
+ def source
226
+ @type = Source
227
+ self
228
+ end
229
+
230
+ def interval
231
+ @type = Interval
232
+ self
233
+ end
234
+
235
+ def identifier
236
+ @type = Identifier
237
+ self
238
+ end
239
+
240
+ def port
241
+ @type = Port
242
+ self
243
+ end
244
+
245
+ def identifiers
246
+ @type = Identifiers
247
+ self
248
+ end
249
+
250
+ def source
251
+ @type = Source
252
+ self
253
+ end
254
+
255
+ def interval
256
+ @type = Interval
257
+ self
258
+ end
259
+
260
+ def addrprefix
261
+ @type = AddrPrefix
262
+ self
263
+ end
264
+
265
+ def address
266
+ @type = Address
267
+ self
268
+ end
269
+
270
+ def addresses
271
+ @type = Addresses
272
+ self
273
+ end
274
+
275
+ def network
276
+ @type = Network
277
+ self
278
+ end
279
+
280
+ def get_default
281
+ @default
282
+ end
283
+
284
+ def default(val)
285
+ @default = val
286
+ self
287
+ end
288
+
289
+ def self.default(val)
290
+ Schema.new.default(val)
291
+ end
292
+
293
+ def self.int
294
+ Schema.new.int
295
+ end
296
+
297
+ def self.boolean
298
+ Schema.new.boolean
299
+ end
300
+
301
+ def self.string
302
+ Schema.new.string
303
+ end
304
+
305
+ def self.interval
306
+ Schema.new.interval
307
+ end
308
+
309
+ def self.source
310
+ Schema.new.source
311
+ end
312
+
313
+ def self.port
314
+ Schema.new.port
315
+ end
316
+
317
+ def self.identifier
318
+ Schema.new.identifier
319
+ end
320
+
321
+ def self.identifiers
322
+ Schema.new.identifiers
323
+ end
324
+
325
+ def self.addresses
326
+ Schema.new.addresses
327
+ end
328
+
329
+ def self.addrprefix
330
+ Schema.new.addrprefix
331
+ end
332
+
333
+ def self.address
334
+ Schema.new.address
335
+ end
336
+
337
+ def self.network
338
+ Schema.new.network
339
+ end
340
+
341
+ def self.key
342
+ Schema.new.key
343
+ end
344
+
345
+ def self.noset
346
+ Schema.new.noset
347
+ end
348
+
349
+ def self.required
350
+ Schema.new.required
351
+ end
352
+ end
353
+ end
354
+ end
355
+ end