junos-ez-stdlib 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/LICENSE +26 -0
  2. data/README.md +181 -0
  3. data/docs/Config_Utils.md +3 -0
  4. data/docs/Facts.md +106 -0
  5. data/docs/Filesys_Utils.md +3 -0
  6. data/docs/IPports.md +3 -0
  7. data/docs/L1ports.md +3 -0
  8. data/docs/L2ports.md +3 -0
  9. data/docs/Providers_Resources.md +304 -0
  10. data/docs/RE_utils.md +3 -0
  11. data/docs/StaticHosts.md +3 -0
  12. data/docs/StaticRoutes.md +3 -0
  13. data/docs/Vlans.md +3 -0
  14. data/examples/config/config_file.rb +72 -0
  15. data/examples/config/config_template_object.rb +81 -0
  16. data/examples/config/config_template_simple.rb +76 -0
  17. data/examples/config/multi_config.rb +60 -0
  18. data/examples/fs_utils.rb +31 -0
  19. data/examples/re_upgrade.rb +90 -0
  20. data/examples/re_utils.rb +30 -0
  21. data/examples/simple.rb +47 -0
  22. data/examples/st_hosts.rb +33 -0
  23. data/examples/vlans.rb +25 -0
  24. data/junos-ez-stdlib.gemspec +15 -0
  25. data/lib/junos-ez/facts/chassis.rb +45 -0
  26. data/lib/junos-ez/facts/ifd_style.rb +14 -0
  27. data/lib/junos-ez/facts/personality.rb +22 -0
  28. data/lib/junos-ez/facts/switch_style.rb +22 -0
  29. data/lib/junos-ez/facts/version.rb +32 -0
  30. data/lib/junos-ez/facts.rb +85 -0
  31. data/lib/junos-ez/ip_ports/classic.rb +149 -0
  32. data/lib/junos-ez/ip_ports.rb +28 -0
  33. data/lib/junos-ez/l1_ports/classic.rb +87 -0
  34. data/lib/junos-ez/l1_ports/switch.rb +134 -0
  35. data/lib/junos-ez/l1_ports.rb +81 -0
  36. data/lib/junos-ez/l2_ports/bridge_domain.rb +0 -0
  37. data/lib/junos-ez/l2_ports/vlan.rb +317 -0
  38. data/lib/junos-ez/l2_ports/vlan_l2ng.rb +0 -0
  39. data/lib/junos-ez/l2_ports.rb +57 -0
  40. data/lib/junos-ez/provider.rb +608 -0
  41. data/lib/junos-ez/stdlib.rb +16 -0
  42. data/lib/junos-ez/system/st_hosts.rb +74 -0
  43. data/lib/junos-ez/system/st_routes.rb +135 -0
  44. data/lib/junos-ez/system/syscfg.rb +103 -0
  45. data/lib/junos-ez/system.rb +98 -0
  46. data/lib/junos-ez/utils/config.rb +205 -0
  47. data/lib/junos-ez/utils/fs.rb +376 -0
  48. data/lib/junos-ez/utils/re.rb +371 -0
  49. data/lib/junos-ez/vlans/bridge_domain.rb +85 -0
  50. data/lib/junos-ez/vlans/vlan.rb +112 -0
  51. data/lib/junos-ez/vlans.rb +31 -0
  52. metadata +111 -0
@@ -0,0 +1,608 @@
1
+ ##### ---------------------------------------------------------------
2
+ ##### The Junos::Ez::Provider and associated Parent class make up
3
+ ##### the main 'framework' of the "EZ" library system. Please
4
+ ##### consider your changes carefully as it will have a large
5
+ ##### scope of impact. Thank you.
6
+ ##### ---------------------------------------------------------------
7
+
8
+ module Junos; end
9
+
10
+ module Junos::Ez
11
+
12
+ VERSION = "0.0.10"
13
+
14
+ ### ---------------------------------------------------------------
15
+ ### rpc_errors - decodes the XML into an array of error/Hash
16
+ ### @@@ TBD: this should be moved into the 'netconf' gem
17
+ ### ---------------------------------------------------------------
18
+
19
+ def self.rpc_errors( as_xml )
20
+ errs = as_xml.xpath('//rpc-error')
21
+ return nil if errs.count == 0 # safety check
22
+
23
+ retval = []
24
+ errs.each do |err|
25
+ err_h = {}
26
+ # every error has a severity and message
27
+ err_h[:severity] = err.xpath('error-severity').text.strip
28
+ err_h[:message] = err.xpath('error-message').text.strip
29
+
30
+ # some have an edit path error
31
+ unless ( err_path = err.xpath('error-path')).empty?
32
+ err_h[:edit_path] = err_path.text.strip
33
+ end
34
+
35
+ # some have addition error-info/bad-element ...
36
+ unless ( bad_i = err.xpath('error-info/bad-element')).empty?
37
+ err_h[:bad_identifier] = bad_i.text.strip
38
+ end
39
+
40
+ retval << err_h
41
+ end
42
+ retval
43
+ end
44
+
45
+ end
46
+
47
+ module Junos::Ez::Provider
48
+
49
+ ## all managed objects have the following properties:
50
+
51
+ PROPERTIES = [
52
+ :_exist, # exists in configuration (or should)
53
+ :_active # active in configuration (or should)
54
+ ]
55
+
56
+ ## 'attach_instance_variable' is the way to dynamically
57
+ ## add an instance variable to the on_obj and "publish"
58
+ ## it in the same way attr_accessor would.
59
+
60
+ def self.attach_instance_variable( on_obj, varsname, new_obj )
61
+ ivar = ("@" + varsname.to_s).to_sym
62
+ on_obj.instance_variable_set( ivar, new_obj )
63
+ on_obj.define_singleton_method( varsname ) do
64
+ on_obj.instance_variable_get( ivar )
65
+ end
66
+ on_obj.providers << varsname
67
+ end
68
+
69
+ end
70
+
71
+ class Junos::Ez::Provider::Parent
72
+
73
+ attr_reader :ndev, :parent, :name
74
+ attr_accessor :providers
75
+ attr_accessor :has, :should, :properties
76
+ attr_accessor :list, :catalog
77
+
78
+ # p_obj - the parent object
79
+ # name - the name of the resource, or nil if this is a provider
80
+ # opts - options to the provider/resource. :parent is reserved
81
+
82
+ def initialize( p_obj, name = nil, opts = {} )
83
+
84
+ @providers = []
85
+ @parent = opts[:parent] || nil
86
+ @ndev = p_obj.instance_variable_get(:@ndev) || p_obj
87
+ @name = name
88
+ @opts = opts
89
+
90
+ @list = [] # array list of item names
91
+ @catalog = {} # hash catalog of named items
92
+
93
+ return unless @name
94
+ # resources only from here ...
95
+ @has = {} # properties read-from Junos
96
+ @should = {} # properties to write-back to Junos
97
+ end
98
+
99
+ ### ---------------------------------------------------------------
100
+ ### 'is_provider?' - indicates if this object instance is a
101
+ ### provider object, rather than a specific instance of the object
102
+ ### ---------------------------------------------------------------
103
+
104
+ def is_provider?; @name.nil? end
105
+
106
+ ### ---------------------------------------------------------------
107
+ ### is_new? - indicates if this is a new resource
108
+ ### ---------------------------------------------------------------
109
+
110
+ def is_new?; (@has[:_exist] == false) || false end
111
+
112
+ ### ---------------------------------------------------------------
113
+ ### [property] resource property reader or
114
+ ### ["name"] resource selector from provider
115
+ ### ---------------------------------------------------------------
116
+
117
+ def []( property )
118
+ return self.select( property ) if is_provider?
119
+
120
+ # if there is already something in the write-back, then use
121
+ # it before using from the read-cache
122
+
123
+ return @should[property] if @should[property]
124
+ return @has[property] if @has
125
+ end
126
+
127
+ ### ---------------------------------------------------------------
128
+ ### []= property writer (@should)
129
+ ### ---------------------------------------------------------------
130
+
131
+ def []=( property, rval )
132
+ raise ArgumentError, "This is not a provider instance" if is_provider?
133
+ raise ArgumentError, "Invalid property['#{property.to_s}']" unless properties.include? property
134
+
135
+ @should[property] = rval
136
+ end
137
+
138
+ ### ---------------------------------------------------------------
139
+ ### 'select' a resource from a provider
140
+ ### ---------------------------------------------------------------
141
+
142
+ def select( name )
143
+ raise ArgumentError, "This is not a provider instance" unless is_provider?
144
+ this = self.class.new( @ndev, name, @opts )
145
+ this.properties = self.properties
146
+ this.read!
147
+ this
148
+ end
149
+
150
+ ### ---------------------------------------------------------------
151
+ ### 'exists?' - does the resource exist in the Juos config
152
+ ### ---------------------------------------------------------------
153
+
154
+ def exists?; @has[:_exist]; end
155
+
156
+ ### ---------------------------------------------------------------
157
+ ### 'active?' - is the resource config active in Junos
158
+ ### ---------------------------------------------------------------
159
+
160
+ def active?
161
+ false unless exists?
162
+ @has[:_active]
163
+ end
164
+
165
+ ### @@@ helper method, probably needs to go into 'private section
166
+ ### @@@ TBD
167
+
168
+ def name_decorated( name = @name )
169
+ self.class.to_s + "['" + name + "']"
170
+ end
171
+
172
+ ### ---------------------------------------------------------------
173
+ ### Provider methods to obtain collection information as
174
+ ### 'list' - array of named items
175
+ ### 'catalog' - hash of all items with properties
176
+ ### ---------------------------------------------------------------
177
+
178
+ def list
179
+ @list.empty? ? list! : @list
180
+ end
181
+
182
+ def list!
183
+ @list.clear
184
+ @list = build_list
185
+ end
186
+
187
+ def catalog
188
+ @catalog.empty? ? catalog! : @catalog
189
+ end
190
+
191
+ def catalog!
192
+ @catalog.clear
193
+ @catalog = build_catalog
194
+ end
195
+
196
+ ### ---------------------------------------------------------------
197
+ ### CREATE methods
198
+ ### ---------------------------------------------------------------
199
+
200
+ ## ----------------------------------------------------------------
201
+ ## 'create' will build a new object, but does not write the
202
+ ## contents back to the device. The caller can chain the
203
+ ## write! method if desired Alternative, the caller
204
+ ## can use 'create!' which does write to the device.
205
+ ## ----------------------------------------------------------------
206
+
207
+ def create( name = nil, prop_hash = {}, &block )
208
+
209
+ ## if this is an existing object, then we shouldn't
210
+ ## allow the caller to create something.
211
+
212
+ raise ArgumentError, "Not called by provider!" unless is_provider?
213
+
214
+ ## if we're here, then we're creating an entirely new
215
+ ## instance of this object. We should check to see if
216
+ ## it first exists, eh? So allow the caller to specify
217
+ ## if they want an exception if it already exists; overloading
218
+ ## the use of the prop_hash[:_exist], yo!
219
+
220
+ newbie = self.select( name )
221
+ if prop_hash[:_exist]
222
+ raise ArgumentError, name_decorated(name) + " already exists" if newbie.exists?
223
+ end
224
+
225
+ prop_hash.each{ |k,v| newbie[k] = v } unless prop_hash.empty?
226
+
227
+ ## default mark the newly created object as should exist and should
228
+ ## be active (if not already set)
229
+
230
+ newbie[:_exist] = true
231
+ newbie[:_active] ||= true
232
+
233
+ ## if a block is provided, then pass the block the new object
234
+ ## the caller is then expected to set the properies
235
+
236
+ yield( newbie ) if block_given?
237
+
238
+ ## return the new object
239
+ return newbie
240
+ end
241
+
242
+ ## ----------------------------------------------------------------
243
+ ## 'create!' is just a helper to call create and then write
244
+ ## the config assuming create returns ok.
245
+ ## ----------------------------------------------------------------
246
+
247
+ def create!( name = nil, prop_hash = {}, &block )
248
+ newbie = create( name, prop_hash, block )
249
+ return nil unless newbie
250
+ newbie.write!
251
+ newbie
252
+ end
253
+
254
+ ## ----------------------------------------------------------------
255
+ ## YAML / HASH methods
256
+ ## ----------------------------------------------------------------
257
+
258
+ def create_from_yaml!( opts = {} )
259
+ raise ArgumentError "Missing :filename param" unless opts[:filename]
260
+ as_hash = YAML.load_file( opts[:filename] )
261
+ write_xml_config! xml_from_h_expanded( as_hash, opts )
262
+ end
263
+
264
+ def create_from_hash!( as_hash, opts = {} )
265
+ write_xml_config! xml_from_h_expanded( as_hash, opts )
266
+ end
267
+
268
+ def to_h_expanded( opts = {} )
269
+ to_h( opts )
270
+ end
271
+
272
+ def to_yaml( opts = {} )
273
+ out_hash = to_h_expanded( opts )
274
+ out_yaml = out_hash.to_yaml
275
+ File.open( opts[:filename], "w" ){|f| f.puts out_hash.to_yaml } if opts[:filename]
276
+ out_yaml
277
+ end
278
+
279
+ ### ---------------------------------------------------------------
280
+ ### 'delete!' will cause the item to be removed from the Junos
281
+ ### configuration
282
+ ### ---------------------------------------------------------------
283
+
284
+ def delete!
285
+ return nil unless exists?
286
+ xml = xml_at_top
287
+ par = xml.instance_variable_get(:@parent)
288
+ par['delete'] = 'delete'
289
+ rsp = write_xml_config!( xml.doc.root )
290
+ @has[:_exist] = false
291
+ true # rsp ... don't return XML, but let's hear from the community...
292
+ end
293
+
294
+ ### ---------------------------------------------------------------
295
+ ### Junos activation controls
296
+ ### ---------------------------------------------------------------
297
+
298
+ def activate!
299
+ return nil if @should[:_active] == true
300
+ @should[:_active] = true
301
+ write!
302
+ end
303
+
304
+ def deactivate!
305
+ return nil if @should[:_active] == false
306
+ @should[:_active] = false
307
+ write!
308
+ end
309
+
310
+ ### ---------------------------------------------------------------
311
+ ### Junos rename element
312
+ ### ---------------------------------------------------------------
313
+
314
+ ## by default, simply allow the new name
315
+ def xml_element_newname( new_name); new_name end
316
+
317
+ def rename!( new_name )
318
+ return nil unless exists?
319
+
320
+ xml = xml_at_top
321
+ par = xml.instance_variable_get(:@parent)
322
+ new_ele_name = xml_element_newname( new_name )
323
+
324
+ return nil unless new_ele_name
325
+
326
+ par['rename'] = 'rename'
327
+ par['name'] = new_ele_name
328
+
329
+ rsp = write_xml_config!( xml.doc.root )
330
+ @name = new_name
331
+ rsp
332
+ end
333
+
334
+ ### ---------------------------------------------------------------
335
+ ### Junos reorder method
336
+ ###
337
+ ### opts[:before] = item-name,
338
+ ### opts[:after] = item-name
339
+ ### ---------------------------------------------------------------
340
+
341
+ def reorder!( opts )
342
+ return nil unless exists?
343
+
344
+ ## validate opts hash
345
+ ctrl, name = opts.first
346
+ raise ArgumentError, "Invalid operation #{ctrl}" unless [:before,:after].include? ctrl
347
+
348
+ xml = xml_at_top
349
+ par = xml.instance_variable_get(:@parent)
350
+ par['insert'] = ctrl.to_s
351
+ par['name'] = name
352
+ rsp = write_xml_config! ( xml.doc.root )
353
+
354
+ return rsp
355
+ end
356
+
357
+ ### ---------------------------------------------------------------
358
+ ### Provider each method - this will go and create a managed
359
+ ### object for each item in the list. This could get CPU
360
+ ### intensive depending on the number of items under provider
361
+ ### management, yo!
362
+ ### ---------------------------------------------------------------
363
+
364
+ def each( &block )
365
+ raise ArgumentError, "not a provider" unless is_provider?
366
+ list.each{ |name| yield select(name ) }
367
+ end
368
+
369
+ ### ---------------------------------------------------------------
370
+ ### Provider reader methods
371
+ ### ---------------------------------------------------------------
372
+
373
+ ## 'init_has' is called when creating a new managed object
374
+ ## or when a caller attempts to retrieve a non-existing one
375
+
376
+ def init_has; nil end
377
+
378
+ ## 'xml_get_has_xml' - used to retrieve the starting location of the
379
+ ## actual XML data for the managed object (as compared to the top
380
+ ## of the configuration document
381
+
382
+ def xml_get_has_xml( xml ); nil end
383
+
384
+ ## 'xml_config_read!' is ued to retrieve the configuration
385
+ ## from the Junos device
386
+
387
+ def xml_config_read!
388
+ @ndev.rpc.get_configuration( xml_at_top )
389
+ end
390
+
391
+ def read!
392
+ @has.clear
393
+ cfg_xml = xml_config_read!
394
+ @has_xml = xml_get_has_xml( cfg_xml )
395
+
396
+ ## if the thing doesn't exist in Junos, then mark the @has
397
+ ## structure accordingly and call the object init_has for
398
+ ## any defaults
399
+
400
+ unless @has_xml
401
+ @has[:_exist] ||= false
402
+ @has[:_active] ||= true
403
+ init_has
404
+ return nil
405
+ end
406
+
407
+ ## xml_read_parser *MUST* be implmented by the provider class
408
+ ## it is used to parse the XML into the HASH structure. It
409
+ ## returns true/false
410
+
411
+ xml_read_parser( @has_xml, @has )
412
+
413
+ ## return the Hash representation
414
+ self.has
415
+ end
416
+
417
+ ### ---------------------------------------------------------------
418
+ ### Provider writer methods
419
+ ### ---------------------------------------------------------------
420
+
421
+ def need_write?; not @should.empty? end
422
+
423
+ def write!
424
+ return nil if @should.empty?
425
+
426
+ @should[:_exist] ||= true
427
+
428
+ # create the necessary chagnes and push them to the Junos
429
+ # device. If an error occurs, it will be raised
430
+
431
+ xml_change = xml_build_change
432
+ return nil unless xml_change
433
+ rsp = write_xml_config!( xml_change )
434
+
435
+ # copy the 'should' values into the 'has' values now that
436
+ # they've been written back to Junos
437
+
438
+ @has.merge! @should
439
+ @should.clear
440
+
441
+ # returning 'true' for now. might need to change this back
442
+ # to 'rsp' depending on the community feedback. general approach is to not have to
443
+ # deal with XML, unless it's an exception case. the only time rsp is really
444
+ # needed is to look at warnings; i.e. not-errors. errors will generate an exception, yo!
445
+
446
+ return true
447
+ end
448
+
449
+ ### ---------------------------------------------------------------
450
+ ### XML writer methods
451
+ ### ---------------------------------------------------------------
452
+
453
+ def xml_at_edit; nil; end
454
+ def xml_at_top; nil; end
455
+ def xml_on_create( xml ); nil; end
456
+ def xml_on_delete( xml ); nil; end
457
+
458
+ def xml_change__exist( xml )
459
+ return xml_on_create( xml ) if @should[:_exist]
460
+
461
+ par = xml.instance_variable_get(:@parent)
462
+ par['delete'] = 'delete'
463
+
464
+ return xml_on_delete( xml )
465
+ end
466
+
467
+ ## 'xml_build_change' is used to create the Junos XML
468
+ ## configuration structure. Generally speaking it
469
+ ## should not be called by code outside the providers,
470
+ ## but sometimes we might want to, so don't make it private
471
+
472
+ def xml_build_change( xml_at_here = nil )
473
+ edit_at = xml_at_here || xml_at_edit || xml_at_top
474
+
475
+ if @should[:_exist] == false
476
+ xml_change__exist( edit_at )
477
+ return edit_at.doc.root
478
+ end
479
+
480
+ changed = false
481
+ @should.keys.each do |prop|
482
+ changed = true if self.send( "xml_change_#{prop}", edit_at )
483
+ end
484
+ (changed) ? edit_at.doc.root : nil
485
+ end
486
+
487
+ ### ---------------------------------------------------------------
488
+ ### XML common write "change" methods
489
+ ### ---------------------------------------------------------------
490
+
491
+ def xml_change_admin( xml )
492
+ xml.disable (@should[:admin] == :up ) ? Netconf::JunosConfig::DELETE : nil
493
+ end
494
+
495
+ def xml_change_description( xml )
496
+ xml_set_or_delete( xml, 'description', @should[:description] )
497
+ end
498
+
499
+ def xml_change__active( xml )
500
+ par = xml.instance_variable_get(:@parent)
501
+ value = @should[:_active] ? 'active' : 'inactive'
502
+ par[value] = value # attribute name is same as value
503
+ end
504
+
505
+ ### ---------------------------------------------------------------
506
+ ### 'to_h' lets us look at the read/write hash structures
507
+ ### ---------------------------------------------------------------
508
+
509
+ def to_h( which = :read )
510
+ { @name => (which == :read) ? @has : @should }
511
+ end
512
+
513
+ ##### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
514
+ ##### !!!!! PRIVATE METHODS !!!!!
515
+ ##### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
516
+
517
+ private
518
+
519
+ def set_has_status( xml, has )
520
+ has[:_active] = xml['inactive'] ? false : true
521
+ has[:_exist] = true
522
+ end
523
+
524
+ ### ---------------------------------------------------------------
525
+ ### write configuration to Junos. Check for errors vs. warnings.
526
+ ### if there are warnings then return the result. If there are
527
+ ### errors, re-throw the exception object. If everything was
528
+ ### OK, simply return the result
529
+ ### ---------------------------------------------------------------
530
+
531
+ def write_xml_config!( xml, opts = {} )
532
+ begin
533
+ action = {'action' => 'replace' }
534
+ result = @ndev.rpc.load_configuration( xml, action )
535
+ rescue Netconf::RpcError => e
536
+ errs = e.rsp.xpath('//rpc-error[error-severity = "error"]')
537
+ raise e unless errs.empty?
538
+ e.rsp
539
+ else
540
+ result
541
+ end
542
+ end
543
+
544
+ def oh_no!
545
+ return if @opts[:ignore_raise]
546
+ yield if block_given? # should always be a block given ...
547
+ end
548
+
549
+ ### ---------------------------------------------------------------
550
+ ### XML property reader/writer for elements that can be present,
551
+ ### or existing with a "no-" prepended. For example "retain" or
552
+ ### "no-retain"
553
+ ### ---------------------------------------------------------------
554
+
555
+ def xml_read_parse_noele( as_xml, ele_name, as_hash, prop )
556
+ unless (ele = as_xml.xpath("#{ele_name} | no-#{ele_name}")).empty?
557
+ as_hash[prop] = (ele[0].name =~ /^no-/) ? false : true
558
+ end
559
+ end
560
+
561
+ def xml_set_or_delete_noele( xml, ele_name, prop = ele_name.to_sym )
562
+
563
+ # delete what was there
564
+ unless @has[prop].nil?
565
+ value_prop = @has[prop]
566
+ wr_ele_name = value_prop ? ele_name : 'no-' + ele_name
567
+ xml.send(wr_ele_name.to_sym, Netconf::JunosConfig::DELETE)
568
+ end
569
+
570
+ # if we're not adding anything back, signal that we've done
571
+ # something, and we're done, yo!
572
+ return true if @should[prop].nil?
573
+
574
+ # add new value
575
+ value_prop = @should[prop]
576
+ ele_name = 'no-' + ele_name if value_prop == false
577
+ xml.send( ele_name.to_sym )
578
+
579
+ end
580
+
581
+ def xml_when_item( xml_item, &block )
582
+ raise ArgumentError, "no block given" unless block_given?
583
+ return unless xml_item[0]
584
+ return yield(xml_item[0]) if block.arity == 1
585
+ yield
586
+ end
587
+
588
+ ### ---------------------------------------------------------------
589
+ ### XML property writer utilities
590
+ ### ---------------------------------------------------------------
591
+
592
+ def xml_set_or_delete( xml, ele_name, value )
593
+ xml.send( ele_name.to_sym, (value ? value : Netconf::JunosConfig::DELETE) )
594
+ end
595
+
596
+ def xml_set_or_delete_element( xml, ele_name, should )
597
+ xml.send( ele_name.to_sym, (should) ? nil : Netconf::JunosConfig::DELETE )
598
+ end
599
+
600
+ def diff_property_array( prop )
601
+ should = @should[prop] || []
602
+ has = @has[prop] || []
603
+ [ should - has, has - should ]
604
+ end
605
+
606
+ end
607
+
608
+
@@ -0,0 +1,16 @@
1
+
2
+ require 'junos-ez/provider' # framework code
3
+ require 'junos-ez/facts' # fact keeper
4
+ require 'junos-ez/system' # various system resources
5
+ require 'junos-ez/l1_ports' # physical ports
6
+ require 'junos-ez/vlans' # vlans
7
+ require 'junos-ez/l2_ports' # switch ports
8
+ require 'junos-ez/ip_ports' # ip ports (v4)
9
+
10
+ # -------------------------------------------------------------------
11
+ # utility libraries, not providers
12
+ # -------------------------------------------------------------------
13
+
14
+ require 'junos-ez/utils/re'
15
+ require 'junos-ez/utils/fs'
16
+ require 'junos-ez/utils/config'
@@ -0,0 +1,74 @@
1
+ class Junos::Ez::StaticHosts::Provider
2
+
3
+ ### ---------------------------------------------------------------
4
+ ### XML top placement
5
+ ### ---------------------------------------------------------------
6
+
7
+ def xml_at_top
8
+ xml = Nokogiri::XML::Builder.new {|xml| xml.configuration {
9
+ xml.system { xml.send('static-host-mapping') {
10
+ xml.name @name
11
+ return xml
12
+ }}
13
+ }}
14
+ end
15
+
16
+ ### ---------------------------------------------------------------
17
+ ### XML property readers
18
+ ### ---------------------------------------------------------------
19
+
20
+ def xml_get_has_xml( xml )
21
+ xml.xpath('//static-host-mapping')[0]
22
+ end
23
+
24
+ def xml_read_parser( as_xml, as_hash )
25
+ set_has_status( as_xml, as_hash )
26
+
27
+ ip_v4 = as_xml.xpath('inet').text
28
+ as_hash[:ip] = ip_v4 unless ip_v4.empty?
29
+
30
+ ip_v6 = as_xml.xpath('inet6').text
31
+ as_hash[:ip6] = ip_v6 unless ip_v6.empty?
32
+ end
33
+
34
+ ### ---------------------------------------------------------------
35
+ ### XML property writers
36
+ ### ---------------------------------------------------------------
37
+
38
+ def xml_change_ip( xml )
39
+ xml_set_or_delete( xml, 'inet', @should[:ip] )
40
+ end
41
+
42
+ def xml_change_ip6( xml )
43
+ xml_set_or_delete( xml, 'inet6', @should[:ip6] )
44
+ end
45
+
46
+ end
47
+
48
+ ##### ---------------------------------------------------------------
49
+ ##### Provider collection methods
50
+ ##### ---------------------------------------------------------------
51
+
52
+ class Junos::Ez::StaticHosts::Provider
53
+
54
+ def build_list
55
+ @ndev.rpc.get_configuration{|xml| xml.system {
56
+ xml.send(:'static-host-mapping')
57
+ }}.xpath('system/static-host-mapping/name').collect do |item|
58
+ item.text
59
+ end
60
+ end
61
+
62
+ def build_catalog
63
+ @catalog = {}
64
+ @ndev.rpc.get_configuration{ |xml| xml.system {
65
+ xml.send(:'static-host-mapping')
66
+ }}.xpath('system/static-host-mapping').each do |item|
67
+ name = item.xpath('name').text
68
+ @catalog[name] = {}
69
+ xml_read_parser( item, @catalog[name] )
70
+ end
71
+ @catalog
72
+ end
73
+
74
+ end