junos-ez-stdlib 0.0.10

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 (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