shopify-junos-ez-stdlib 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +91 -0
  3. data/LICENSE +26 -0
  4. data/README.md +199 -0
  5. data/docs/Facts.md +192 -0
  6. data/docs/Providers/Group.md +61 -0
  7. data/docs/Providers/IPports.md +61 -0
  8. data/docs/Providers/L1ports.md +29 -0
  9. data/docs/Providers/L2ports.md +43 -0
  10. data/docs/Providers/LAGports.md +57 -0
  11. data/docs/Providers/StaticHosts.md +26 -0
  12. data/docs/Providers/StaticRoutes.md +37 -0
  13. data/docs/Providers/UserAuths.md +32 -0
  14. data/docs/Providers/Users.md +122 -0
  15. data/docs/Providers/Vlans.md +43 -0
  16. data/docs/Providers_Resources.md +353 -0
  17. data/docs/README_FIRST.md +27 -0
  18. data/docs/Utils/Config.md +160 -0
  19. data/docs/Utils/Filesystem.md +360 -0
  20. data/docs/Utils/Routing-Engine.md +379 -0
  21. data/docs/Utils/SCP.md +24 -0
  22. data/examples/config/config_file.rb +72 -0
  23. data/examples/config/config_template_object.rb +81 -0
  24. data/examples/config/config_template_simple.rb +76 -0
  25. data/examples/config/multi_config.rb +60 -0
  26. data/examples/fs_utils.rb +31 -0
  27. data/examples/lag_port.rb +27 -0
  28. data/examples/re_upgrade.rb +99 -0
  29. data/examples/re_utils.rb +33 -0
  30. data/examples/simple.rb +46 -0
  31. data/examples/st_hosts.rb +33 -0
  32. data/examples/user.rb +32 -0
  33. data/examples/vlans.rb +31 -0
  34. data/junos-ez-stdlib.gemspec +15 -0
  35. data/lib/junos-ez/exceptions.rb +3 -0
  36. data/lib/junos-ez/facts.rb +83 -0
  37. data/lib/junos-ez/facts/chassis.rb +51 -0
  38. data/lib/junos-ez/facts/ifd_style.rb +17 -0
  39. data/lib/junos-ez/facts/personality.rb +25 -0
  40. data/lib/junos-ez/facts/switch_style.rb +31 -0
  41. data/lib/junos-ez/facts/version.rb +58 -0
  42. data/lib/junos-ez/group.rb +206 -0
  43. data/lib/junos-ez/ip_ports.rb +30 -0
  44. data/lib/junos-ez/ip_ports/classic.rb +188 -0
  45. data/lib/junos-ez/l1_ports.rb +121 -0
  46. data/lib/junos-ez/l1_ports/classic.rb +87 -0
  47. data/lib/junos-ez/l1_ports/switch.rb +134 -0
  48. data/lib/junos-ez/l2_ports.rb +66 -0
  49. data/lib/junos-ez/l2_ports/bridge_domain.rb +499 -0
  50. data/lib/junos-ez/l2_ports/vlan.rb +433 -0
  51. data/lib/junos-ez/l2_ports/vlan_l2ng.rb +502 -0
  52. data/lib/junos-ez/lag_ports.rb +268 -0
  53. data/lib/junos-ez/provider.rb +619 -0
  54. data/lib/junos-ez/stdlib.rb +18 -0
  55. data/lib/junos-ez/system.rb +48 -0
  56. data/lib/junos-ez/system/st_hosts.rb +92 -0
  57. data/lib/junos-ez/system/st_routes.rb +159 -0
  58. data/lib/junos-ez/system/syscfg.rb +103 -0
  59. data/lib/junos-ez/system/userauths.rb +84 -0
  60. data/lib/junos-ez/system/users.rb +217 -0
  61. data/lib/junos-ez/utils/config.rb +236 -0
  62. data/lib/junos-ez/utils/fs.rb +385 -0
  63. data/lib/junos-ez/utils/re.rb +558 -0
  64. data/lib/junos-ez/version.rb +6 -0
  65. data/lib/junos-ez/vlans.rb +38 -0
  66. data/lib/junos-ez/vlans/bridge_domain.rb +89 -0
  67. data/lib/junos-ez/vlans/vlan.rb +119 -0
  68. data/lib/junos-ez/vlans/vlan_l2ng.rb +126 -0
  69. data/shipit.yml +4 -0
  70. data/tmp +7 -0
  71. metadata +129 -0
@@ -0,0 +1,385 @@
1
+ =begin
2
+ ---------------------------------------------------------------------
3
+ FS::Utils is a collection of filesystem utility routines. These do
4
+ not map to configuration resources. However, the provider framework
5
+ lends itself well in case we need to do something later, yo!
6
+
7
+ Each of the FS::Util methods will provide back a rubyized structure
8
+ by default. The 'options' hash to each method will allow you to
9
+ change the return result in either :text or Junos :xml as well.
10
+
11
+ The following is a quick list of the filesystem utility methods,
12
+ these following the unix naming counterparts (mostly)
13
+
14
+ cat - returns the contents of the file (String)
15
+ checksum - returns the checksum of a file
16
+ cleanup? - returns Hash info of files that would be removed by ...
17
+ cleanup! - performs a system storage cleanup
18
+ cp! - local file copy (use 'scp' if you want to copy remote/local)
19
+ cwd - change the working directory (String)
20
+ df - shows the system storage (Hash)
21
+ ls - returns a filesystem listing (Hash)
22
+ mv! - rename/move files (true | String error)
23
+ pwd - return the current working directory (String)
24
+ rm! - remove files (String)
25
+
26
+ ---------------------------------------------------------------------
27
+ =end
28
+
29
+ module Junos::Ez::FS
30
+ def self.Utils( ndev, varsym )
31
+ newbie = Junos::Ez::FS::Provider.new( ndev )
32
+ Junos::Ez::Provider.attach_instance_variable( ndev, varsym, newbie )
33
+ end
34
+ end
35
+
36
+ ### -----------------------------------------------------------------
37
+ ### PUBLIC METHODS
38
+ ### -----------------------------------------------------------------
39
+ ### class containing filesystem public utility functions
40
+ ### these are not in alphabetical order, but I should do that, yo!
41
+ ### -----------------------------------------------------------------
42
+
43
+ class Junos::Ez::FS::Provider < Junos::Ez::Provider::Parent
44
+
45
+ ### -------------------------------------------------------------
46
+ ### cwd - change the current working directory. This method will
47
+ ### return the String of the new working directory or raise
48
+ ### and IOError exception if the directory is invalid
49
+ ### -------------------------------------------------------------
50
+
51
+ def cwd( directory )
52
+ begin
53
+ got = @ndev.rpc.set_cli_working_directory( :directory => directory )
54
+ rescue => e
55
+ raise IOError, "invalid directory: #{directory}"
56
+ else
57
+ got.xpath('working-directory').text
58
+ end
59
+ end
60
+
61
+ ### -------------------------------------------------------------
62
+ ### pwd - retrieve current working directory, return String
63
+ ### -------------------------------------------------------------
64
+
65
+ def pwd
66
+ ndev.rpc.command("show cli directory").text.strip
67
+ end
68
+
69
+ def checksum( method, path )
70
+ got = case method
71
+ when :md5
72
+ @ndev.rpc.get_checksum_information( :path => path )
73
+ when :sha256
74
+ @ndev.rpc.get_sha256_checksum_information( :path => path )
75
+ when :sha1
76
+ @ndev.rpc.get_sha1_checksum_information( :path => path )
77
+ end
78
+
79
+ f_chk = got.xpath('file-checksum')
80
+ if (err = f_chk.xpath('rpc-error/error-message')[0])
81
+ raise IOError, err.text.strip
82
+ end
83
+ f_chk.xpath('checksum').text.strip
84
+ end
85
+
86
+ ### -------------------------------------------------------------
87
+ ## ls - provides directory listing of files/subdirs. if
88
+ ## directory is nil, then the current working directory
89
+ ## is used. The following options (opts) are supported
90
+ ##
91
+ ## :format => [:text, :xml, :hash], default = :hash
92
+ ## :recurse => true - recursive listing thru subdirs
93
+ ## :detail => true - file details, on if :recurse
94
+ ### -------------------------------------------------------------
95
+
96
+ def ls( *args )
97
+
98
+ directory = nil
99
+ opts = {}
100
+
101
+ case args.count
102
+ when 1
103
+ if args[0].kind_of? Hash
104
+ opts = args[0]
105
+ else
106
+ directory = args[0]
107
+ end
108
+ when 2
109
+ directory = args[0]
110
+ opts = args[1]
111
+ end
112
+
113
+ # args are the RPC arguments ...
114
+ args = {}
115
+ args[:path] = directory if directory
116
+ args[:recursive] = true if opts[:recurse]
117
+ args[:detail] = true if opts[:detail]
118
+ args.delete(:detail) if( args[:detail] and args[:recursive])
119
+
120
+ # RPC output format, default is XML
121
+ outf = { :format => 'text' } if opts[:format] == :text
122
+
123
+ got = @ndev.rpc.file_list( args, outf )
124
+ return nil unless got
125
+
126
+ return got.text if opts[:format] == :text
127
+ return got if opts[:format] == :xml
128
+
129
+ # if we're here, then we need to conver the output
130
+ # to a Hash. Joy!
131
+
132
+ collect_detail = args[:detail] || args[:recursive]
133
+
134
+ ls_hash = {}
135
+ got.xpath('directory').each do |dir|
136
+
137
+ dir_name = dir.xpath('directory-name').text.strip
138
+ dir_hash = {}
139
+
140
+ dir_hash[:fileblocks] = dir.xpath('total-file-blocks').text.to_i
141
+ files_info = dir.xpath('file-information')
142
+
143
+ dir_hash[:files] = {}
144
+ dir_hash[:dirs] = {} # sub-directories
145
+
146
+ files_info.each do |file|
147
+ f_name = file.xpath('file-name').text.strip
148
+ f_h = {}
149
+
150
+ if file.xpath('file-directory')[0]
151
+ dir_hash[:dirs][f_name] = f_h
152
+ else
153
+ dir_hash[:files][f_name] = f_h
154
+ end
155
+
156
+ next unless collect_detail
157
+
158
+ f_h[:owner] = file.xpath('file-owner').text.strip
159
+ f_h[:group] = file.xpath('file-group').text.strip
160
+ f_h[:links] = file.xpath('file-links').text.to_i
161
+ f_h[:size] = file.xpath('file-size').text.to_i
162
+
163
+ xml_when_item(file.xpath('file-symlink-target')) { |i|
164
+ f_h[:symlink] = i.text.strip
165
+ }
166
+
167
+ fp = file.xpath('file-permissions')[0]
168
+ f_h[:permissions_text] = fp.attribute('format').value
169
+ f_h[:permissions] = fp.text.to_i
170
+
171
+ fd = file.xpath('file-date')[0]
172
+ f_h[:date] = fd.attribute('format').value
173
+ f_h[:date_epoc] = fd.text.to_i
174
+
175
+ end # each directory file
176
+ ls_hash[ dir_name ] = dir_hash
177
+ end # each directory
178
+
179
+ return nil if ls_hash.empty?
180
+ ls_hash
181
+ end # method: ls
182
+
183
+
184
+ ### -------------------------------------------------------------
185
+ ### cat - is used to obtain the text contents of the file
186
+ ### -------------------------------------------------------------
187
+
188
+ def cat( filename )
189
+ begin
190
+ @ndev.rpc.file_show( :filename => filename ).text
191
+ rescue => e
192
+ raise IOError, e.rsp.xpath('rpc-error/error-message').text.strip
193
+ end
194
+ end
195
+
196
+
197
+
198
+ ### -------------------------------------------------------------
199
+ ### df - shows the system storage information
200
+ ###
201
+ ### opts[:format] = [:text, :xml, :hash]
202
+ ### defaults :hash
203
+ ###
204
+ ### opts[:size_div] = value to device size values,
205
+ ### valid only for :format == :hash
206
+ ### -------------------------------------------------------------
207
+
208
+ def df( opts = {} )
209
+
210
+ outf = {:format => 'text' } if opts[:format] == :text
211
+ args = { :detail => true } if opts[:size_div]
212
+
213
+ got = @ndev.rpc.get_system_storage( args, outf )
214
+
215
+ return got.text if opts[:format] == :text
216
+ return got if opts[:format] == :xml
217
+
218
+ df_h = {}
219
+ ### need to turn this into a Hash
220
+ got.xpath('filesystem').each do |fs|
221
+ fs_name = fs.xpath('filesystem-name').text.strip
222
+ fs_h = {}
223
+ df_h[fs_name] = fs_h
224
+
225
+ fs_h[:mounted_on] = fs.xpath('mounted-on').text.strip
226
+ datum = fs.xpath('total-blocks')
227
+ fs_h[:total_blocks] = datum.text.to_i
228
+ fs_h[:total_size] = datum.attribute('format').value
229
+
230
+ datum = fs.xpath('used-blocks')
231
+ fs_h[:used_blocks] = datum.text.to_i
232
+ fs_h[:used_size] = datum.attribute('format').value
233
+ fs_h[:used_percent] = fs.xpath('used-percent').text.to_i
234
+
235
+ datum = fs.xpath('available-blocks')
236
+ fs_h[:avail_blocks] = datum.text.to_i
237
+ fs_h[:avail_size] = datum.attribute('format').value
238
+ if opts[:size_div]
239
+ fs_h[:total_size] = fs_h[:total_size].to_i / opts[:size_div]
240
+ fs_h[:used_size] = fs_h[:used_size].to_i / opts[:size_div]
241
+ fs_h[:avail_size] = fs_h[:avail_size].to_i / opts[:size_div]
242
+ end
243
+ end
244
+ df_h
245
+ end
246
+
247
+ ### -------------------------------------------------------------
248
+ ### cleanup! will perform the 'request system storage cleanup'
249
+ ### command and remove the files. If you want to check which
250
+ ### files will be removed, use the cleanup? method first
251
+ ### -------------------------------------------------------------
252
+
253
+ def cleanup!
254
+ got = @ndev.rpc.request_system_storage_cleanup
255
+ gone_h = {}
256
+ got.xpath('file-list/file').each do |file|
257
+ _cleanup_file_to_h( file, gone_h )
258
+ end
259
+ gone_h
260
+ end
261
+
262
+ ### -------------------------------------------------------------
263
+ ### 'cleanup?' will return information on files that would be
264
+ ### removed if cleanup! was executed
265
+ ### -------------------------------------------------------------
266
+
267
+ def cleanup?
268
+ got = @ndev.rpc.request_system_storage_cleanup( :dry_run => true )
269
+ dryrun_h = {}
270
+ got.xpath('file-list/file').each do |file|
271
+ _cleanup_file_to_h( file, dryrun_h )
272
+ end
273
+ dryrun_h
274
+ end
275
+
276
+ ### -------------------------------------------------------------
277
+ ### cp! - copies a file. The from_file and to_file can be
278
+ ### URL parameters, yo!
279
+ ###
280
+ ### opts[:source_address] will set the source address of the
281
+ ### copy command, useful when URL contain SCP, HTTP
282
+ ### -------------------------------------------------------------
283
+
284
+ def cp!( from_file, to_file, opts = {} )
285
+ args = { :source => from_file, :destination => to_file }
286
+ args[:source_address] = opts[:source_address] if opts[:source_address]
287
+
288
+ begin
289
+ got = @ndev.rpc.file_copy( args )
290
+ rescue => e
291
+ raise IOError, e.rsp.xpath('rpc-error/error-message').text.strip
292
+ else
293
+ return true
294
+ end
295
+ end
296
+
297
+ ### -------------------------------------------------------------
298
+ ### 'mv' - just like unix, moves/renames a file
299
+ ### -------------------------------------------------------------
300
+
301
+ def mv!( from_path, to_path )
302
+ got = @ndev.rpc.command( "file rename #{from_path} #{to_path}" )
303
+ return true if got.nil? # got no error
304
+ raise IOError, got.text
305
+ end
306
+
307
+ ### -------------------------------------------------------------
308
+ ### rm! - just like unix, removes files
309
+ ### -------------------------------------------------------------
310
+
311
+ def rm!( path )
312
+ got = @ndev.rpc.file_delete( :path => path )
313
+ return true if got.nil? # got no error
314
+ # otherwise, there was an error, check output
315
+ raise IOError, got.text
316
+ end
317
+
318
+
319
+ end # class Provider
320
+
321
+ ### -----------------------------------------------------------------
322
+ ### PRIVATE METHODS
323
+ ### -----------------------------------------------------------------
324
+ ### These are helper/private methods, or methods that are current
325
+ ### work-in-progress/under-investigation
326
+ ### -----------------------------------------------------------------
327
+
328
+ class Junos::Ez::FS::Provider
329
+ private
330
+
331
+ ### private method used to convert 'cleanup' file XML
332
+ ### to hash structure and bind it to collecting hash
333
+
334
+ def _cleanup_file_to_h( file, attach_h )
335
+ file_name = file.xpath('file-name').text.strip
336
+ file_h = {}
337
+ data = file.xpath('size')
338
+ file_h[:size_text] = data.attribute('format').value
339
+ file_h[:size] = data.text.to_i
340
+ file_h[:date] = file.xpath('date').text.strip
341
+ attach_h[file_name] = file_h
342
+ file_h
343
+ end
344
+
345
+ ##### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
346
+ ##### ... HERE THERE BE MONSTERS ....
347
+ ##### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
348
+
349
+ ### -------------------------------------------------------------
350
+ ### 'diff' just like unix; patch output
351
+ ### @@@ something is getting messed up in the XML translation
352
+ ### @@@ as control characters like (<,>) are getting munged.
353
+ ### @@@ need to investigate with Nokogiri ....
354
+ ### -------------------------------------------------------------
355
+
356
+ def diff___( from_file, to_file )
357
+ raise StandardError, "Under investigation"
358
+ got = @ndev.rpc.file_compare( :from_file => from_file, :to_file => to_file )
359
+ end
360
+
361
+ # create a .tar file from the files in the given directory.
362
+ # the filename does not need to include the .tar extension, but
363
+ # if you include it, that's ok.
364
+ # NOTE: cannot specify an arbitrary list of files, per Junos RPC
365
+
366
+ ### !!!! these are only allowed from the CLI, at least as tested
367
+ ### !!!! on an vSRX. Need to check on other platforms, etc.
368
+
369
+ def tar___( directory, filename )
370
+ raise StandardError, "Under investigation"
371
+ got = @ndev.rpc.file_archive( :destination => filename, :source => directory )
372
+ end
373
+
374
+ # create a .tgz file from the files in the given directory.
375
+ # the filename does not need to include the .tgz extension, but
376
+ # if you include it, that's ok.
377
+ # NOTE: cannot specify an arbitrary list of files, per Junos RPC
378
+
379
+ def tgz___( directory, filename )
380
+ raise StandardError, "Under investigation"
381
+ got = @ndev.rpc.file_archive( :destination => filename, :source => directory, :compress => true )
382
+ end
383
+
384
+ end
385
+
@@ -0,0 +1,558 @@
1
+ =begin
2
+ ---------------------------------------------------------------------
3
+
4
+ This file contains routing-engine utility methods. These are
5
+ a misc. collection of methods that perform basic automation tasks
6
+ like upgrading software or getting process information. The
7
+ following lists the methods and the equivalent Junos CLI commands
8
+
9
+ - status show chassis routing-engine
10
+ - uptime show system uptime
11
+ - system_alarms show system alarms
12
+ - chassis_alarms show chassis alarms
13
+ - memory show system memeory
14
+ - users show system users
15
+
16
+ - software_install! request system software add
17
+ - software_rollback! request system software rollback
18
+ - software_validate? request system software validate
19
+ - software_images - provides image file names for current/rollback
20
+
21
+ - license_install! request system license add !! TBD !!
22
+ - license_rm! request system license delete
23
+ - license_save request system license save !! TBD !!
24
+ - licenses show system license
25
+
26
+ - reboot!: request system reboot (no confirm!!)
27
+ - shutdown!: request system power-off (no confirm!!)
28
+
29
+ ---------------------------------------------------------------------
30
+ =end
31
+
32
+ module Junos::Ez::RE
33
+ def self.Utils( ndev, varsym )
34
+ newbie = Junos::Ez::RE::Provider.new( ndev )
35
+ Junos::Ez::Provider.attach_instance_variable( ndev, varsym, newbie )
36
+ end
37
+ end
38
+
39
+ ### -----------------------------------------------------------------
40
+ ### PUBLIC METHODS
41
+ ### -----------------------------------------------------------------
42
+ ### class containing filesystem public utility functions
43
+ ### these are not in alphabetical order, but I should do that, yo!
44
+ ### -----------------------------------------------------------------
45
+
46
+ class Junos::Ez::RE::Provider < Junos::Ez::Provider::Parent
47
+
48
+ ### ---------------------------------------------------------------
49
+ ### status - show chassis routing-engine information
50
+ ### ---------------------------------------------------------------
51
+
52
+ def status( opts = {} )
53
+ got = @ndev.rpc.get_route_engine_information
54
+ status_h = {}
55
+ got.xpath('//route-engine').each do |re|
56
+ re_h = {}
57
+ slot_id = "re" + re.xpath('slot').text
58
+ status_h[slot_id] = re_h
59
+
60
+ re_h[:model] = re.xpath('model').text.strip
61
+ re_h[:serialnumber] = re.xpath('serial-number').text.strip
62
+
63
+ xml_when_item(re.xpath('mastership-state')){|i| re_h[:mastership] = i.text.strip}
64
+
65
+ re_h[:temperature] = {
66
+ :system => re.xpath('temperature').text.strip,
67
+ :cpu => re.xpath('cpu-temperature').text.strip
68
+ }
69
+ re_h[:memory] = {
70
+ :total_size => re.xpath('memory-dram-size').text.to_i,
71
+ :buffer_util => re.xpath('memory-buffer-itilization').text.to_i
72
+ }
73
+ re_h[:cpu_util] = {
74
+ :user => re.xpath('cpu-user').text.to_i,
75
+ :background => re.xpath('cpu-background').text.to_i,
76
+ :system => re.xpath('cpu-system').text.to_i,
77
+ :interrupt => re.xpath('cpu-interrupt').text.to_i,
78
+ :idle => re.xpath('cpu-idle').text.to_i,
79
+ }
80
+ re_h[:uptime] = {
81
+ :at => re.xpath('start-time').text.strip,
82
+ :ago => re.xpath('up-time').text.strip,
83
+ :reboot_reason => re.xpath('last-reboot-reason').text.strip
84
+ }
85
+ re_h[:load_avg] = [
86
+ re.xpath('load-average-one').text.to_f,
87
+ re.xpath('load-average-five').text.to_f,
88
+ re.xpath('load-average-fifteen').text.to_f
89
+ ]
90
+ end
91
+ status_h
92
+ end
93
+
94
+ ### ---------------------------------------------------------------
95
+ ### uptime - show system uptime information
96
+ ### ---------------------------------------------------------------
97
+
98
+ def uptime
99
+ up_h = {}
100
+ got = @ndev.rpc.get_system_uptime_information
101
+ unless (n_re = got.xpath('multi-routing-engine-item')).empty?
102
+ n_re.each do |this_re|
103
+ as_xml = this_re.xpath('system-uptime-information')
104
+ re_name = this_re.xpath('re-name').text.strip
105
+ up_h[re_name] = {}
106
+ _uptime_to_h( as_xml, up_h[re_name] )
107
+ end
108
+ else
109
+ up_h['re0'] = {}
110
+ _uptime_to_h( got, up_h['re0'] )
111
+ end
112
+ up_h
113
+ end
114
+
115
+ ### ---------------------------------------------------------------
116
+ ### system_alarms - show system alarms
117
+ ### ---------------------------------------------------------------
118
+
119
+ def system_alarms
120
+ got = @ndev.rpc.get_system_alarm_information
121
+ alarms_a = []
122
+ got.xpath('alarm-detail').each do |alarm|
123
+ alarm_h = {}
124
+ _alarm_info_to_h( alarm, alarm_h )
125
+ alarms_a << alarm_h
126
+ end
127
+ return nil if alarms_a.empty?
128
+ alarms_a
129
+ end
130
+
131
+ ### ---------------------------------------------------------------
132
+ ### chassis_alarms - show chassis alarms
133
+ ### ---------------------------------------------------------------
134
+
135
+ def chassis_alarms
136
+ got = @ndev.rpc.get_alarm_information
137
+ alarms_a = []
138
+ got.xpath('alarm-detail').each do |alarm|
139
+ alarm_h = {}
140
+ _alarm_info_to_h( alarm, alarm_h )
141
+ alarms_a << alarm_h
142
+ end
143
+ return nil if alarms_a.empty?
144
+ alarms_a
145
+ end
146
+
147
+ ### ---------------------------------------------------------------
148
+ ### memory - show system memory
149
+ ### ---------------------------------------------------------------
150
+
151
+ def memory
152
+ got = @ndev.rpc.get_system_memory_information
153
+ ret_h = {}
154
+ unless (n_re = got.xpath('multi-routing-engine-item')).empty?
155
+ n_re.each do |this_re|
156
+ as_xml = this_re.xpath('system-memory-information')[0]
157
+ re_name = this_re.xpath('re-name').text.strip
158
+ ret_h[re_name] = {}
159
+ _system_memory_to_h( as_xml, ret_h[re_name] )
160
+ end
161
+ else
162
+ ret_h['re0'] = {}
163
+ _system_memory_to_h( got, ret_h['re0'] )
164
+ end
165
+ ret_h
166
+ end
167
+
168
+ ### ---------------------------------------------------------------
169
+ ### users - show system users
170
+ ### ---------------------------------------------------------------
171
+
172
+ def users
173
+ got = @ndev.rpc.get_system_users_information
174
+ users_a = []
175
+ got.xpath('uptime-information/user-table/user-entry').each do |user|
176
+ user_h = {}
177
+ users_a << user_h
178
+
179
+ user_h[:name] = user.xpath('user').text.strip
180
+ user_h[:tty] = user.xpath('tty').text.strip
181
+ user_h[:from] = user.xpath('from').text.strip
182
+ user_h[:login_time] = user.xpath('login-time').text.strip
183
+ user_h[:idle_time] = user.xpath('idel-time').text.strip
184
+ user_h[:idle_time] = nil if user_h[:idle_time].empty?
185
+ user_h[:command] = user.xpath('command').text.strip
186
+ end
187
+ users_a
188
+ end
189
+
190
+ ### ===============================================================
191
+ ###
192
+ ### Software related methods
193
+ ###
194
+ ### ===============================================================
195
+
196
+ ### ---------------------------------------------------------------
197
+ ### software_validate? - request system software validate ...
198
+ ### ---------------------------------------------------------------
199
+
200
+ def software_validate?( package )
201
+ got = @ndev.rpc.request_package_validate(:package_name => package).parent
202
+ errcode = got.xpath('package-result').text.to_i
203
+ return true if errcode == 0
204
+
205
+ # otherwise return the output error message
206
+ got.xpath('output').text.strip
207
+ end
208
+
209
+ ### ---------------------------------------------------------------
210
+ ### software_install! - request system software add ...
211
+ ### ---------------------------------------------------------------
212
+
213
+ def software_install!( opts = {} )
214
+ raise ArgumentError "missing :package" unless opts[:package]
215
+
216
+ args = { :package_name => opts[:package] }
217
+ args[:no_validate] = true if opts[:no_validate]
218
+ args[:unlink] = true if opts[:unlink]
219
+ args[:reboot] = true if opts[:reboot]
220
+
221
+ got = @ndev.rpc.request_package_add( args ).parent
222
+ errcode = got.xpath('package-result').text.to_i
223
+ return true if errcode == 0
224
+
225
+ # otherwise return the output error message
226
+ got.xpath('output').text.strip
227
+ end
228
+
229
+ ### ---------------------------------------------------------------
230
+ ### software_rollback! - request system software rollback
231
+ ### ---------------------------------------------------------------
232
+
233
+ def software_rollback!
234
+ got = @ndev.rpc.request_package_rollback
235
+ got.text.strip
236
+ end
237
+
238
+ def software_images
239
+ ls_pkgs = @ndev.rpc.file_list(:path=>'/packages')
240
+ symlink = ls_pkgs.xpath('//file-symlink-target')[0]
241
+ if symlink
242
+ ls_pkgs = @ndev.rpc.file_list(:path => symlink.text.strip)
243
+ end
244
+
245
+ junos_symlink = ls_pkgs.xpath('//file-information[normalize-space(file-name) = "junos"]')[0]
246
+ junos_old_symlink = ls_pkgs.xpath('//file-information[normalize-space(file-name) = "junos.old"]')[0]
247
+
248
+ ret_h = {}
249
+ ret_h[:rollback] = (junos_old_symlink) ? junos_old_symlink.xpath('file-symlink-target').text.strip : nil
250
+ ret_h[:current] = (junos_symlink) ? junos_symlink.xpath('file-symlink-target').text.strip : ret_h[:rollback]
251
+
252
+ ret_h
253
+ end
254
+
255
+ ### ===============================================================
256
+ ###
257
+ ### Misc Routing Engine Commands & Controls
258
+ ###
259
+ ### ===============================================================
260
+
261
+ ### ---------------------------------------------------------------
262
+ ### reboot! - request system reboot (no confirm!!)
263
+ ### ---------------------------------------------------------------
264
+
265
+ def reboot!( opts = {} )
266
+ arg_options = [:in, :at]
267
+ args = {}
268
+ opts.each do |k,v|
269
+ if arg_options.include? k
270
+ args[k] = v
271
+ else
272
+ raise ArgumentError, "unrecognized option #{k}"
273
+ end
274
+ end
275
+ got = @ndev.rpc.request_reboot( args )
276
+ got.xpath('request-reboot-status').text.strip
277
+ end
278
+
279
+ ### ---------------------------------------------------------------
280
+ ### shutdown! - request system power-off (no confirm!!)
281
+ ### ---------------------------------------------------------------
282
+
283
+ def shutdown!( opts = {} )
284
+ arg_options = [:in, :at]
285
+ args = {}
286
+ opts.each do |k,v|
287
+ if arg_options.include? k
288
+ args[k] = v
289
+ else
290
+ raise ArgumentError, "unrecognized option #{k}"
291
+ end
292
+ end
293
+ ## some Junos devices will throw an RPC error exception which is really
294
+ ## a warning, and some do not. So we need to trap that here.
295
+ begin
296
+ got = @ndev.rpc.request_power_off( args )
297
+ rescue => e
298
+ retmsg = e.rsp.xpath('//error-message').text.strip + "\n"
299
+ return retmsg + e.rsp.xpath('//request-reboot-status').text.strip
300
+ end
301
+ got.xpath('//request-reboot-status').text.strip
302
+ end
303
+
304
+ def ping( host, opts = {} )
305
+ arg_options = [
306
+ :do_not_fragment, :inet, :inet6, :strict,
307
+ :count, :interface, :interval, :mac_address,
308
+ :routing_instance, :size, :source, :tos, :ttl, :wait
309
+ ]
310
+
311
+ args = {:host => host}
312
+ opts.each do |k,v|
313
+ if arg_options.include? k
314
+ args[k] = v
315
+ else
316
+ raise ArgumentError, "unrecognized option #{k}"
317
+ end
318
+ end
319
+
320
+ args[:count] ||= 1
321
+
322
+ got = @ndev.rpc.ping( args )
323
+ return true if got.xpath('ping-success')[0]
324
+
325
+ # if the caller privded a 'failure block' then call that now,
326
+ # otherwise, just return false
327
+
328
+ return (block_given?) ? yield(got) : false
329
+ end
330
+
331
+ ### ===============================================================
332
+ ###
333
+ ### License related methods
334
+ ###
335
+ ### ===============================================================
336
+
337
+ ## ----------------------------------------------------------------
338
+ ## - retrieve Hash of license information.
339
+ ##
340
+ ## By default this will provide the license installed
341
+ ## information.
342
+ ##
343
+ ## --- returns ---
344
+ ## - Hash of data if there are licenses
345
+ ## - nil if no licenses
346
+ ##
347
+ ## --- options ---
348
+ ## :keys => true
349
+ ## Will include the key-text for the license
350
+ ##
351
+ ## ----------------------------------------------------------------
352
+
353
+ def licenses( opts = {} )
354
+
355
+ got = @ndev.rpc.get_license_summary_information
356
+ licenses = got.xpath('license-information/license')
357
+ return nil if licenses.empty?
358
+
359
+ ret_h = {}
360
+ licenses.each do |lic|
361
+ lic_h = {}
362
+ ret_h[lic.xpath('name').text.strip] = lic_h
363
+
364
+ lic_h[:state] = lic.xpath('license-state').text.strip
365
+ lic_h[:version] = lic.xpath('license-version').text.strip
366
+ lic_h[:serialnumber] = lic.xpath('software-sn').text.strip
367
+ lic_h[:customer] = lic.xpath('customer-reference').text.strip
368
+
369
+ features = lic.xpath('feature-block/feature')
370
+ unless features.empty?
371
+ feats_h = {}
372
+ lic_h[:features] = feats_h
373
+ features.each do |feat|
374
+ feat_h = {}
375
+ feats_h[feat.xpath('name').text.strip] = feat_h
376
+ feat_h[:description] = feat.xpath('description').text.strip
377
+ v_info = feat.xpath('validity-information')[0]
378
+ case v_info.xpath('validity-type').text.strip
379
+ when 'date-based'
380
+ feat_h[:date_start] = v_info.xpath('start-date').text.strip
381
+ feat_h[:date_end] = v_info.xpath('end-date').text.strip
382
+ end
383
+ end # each features
384
+ end # if features
385
+ end # each license
386
+
387
+ ## now check to see if the :keys have been requested. if so
388
+ ## then get that data, and store back into the return Hash.
389
+
390
+ if opts[:keys]
391
+ got = @ndev.rpc.get_license_key_information
392
+ got.xpath('license-key').each do |key|
393
+ name = key.xpath('name').text.strip
394
+ ret_h[name][:key] = key.xpath('key-data').text
395
+ end
396
+ end
397
+
398
+ ret_h
399
+ end
400
+
401
+ ## ----------------------------------------------------------------
402
+ ## add a license
403
+ ##
404
+ ## --- returns ---
405
+ ## true - key added OK
406
+ ## String - error message otherwise
407
+ ##
408
+ ## --- options ---
409
+ ## :key => String
410
+ ## The key text
411
+ ##
412
+ ## :filename => String
413
+ ## Path to licence-file on server
414
+ ## ----------------------------------------------------------------
415
+
416
+ def license_install!( opts = {} )
417
+ args = {}
418
+ if opts[:key]
419
+ args[:key_data] = opts[:key]
420
+ elsif opts[:filename]
421
+ args[:key_data] = File.read(opts[:filename]).strip
422
+ end
423
+ got = @ndev.rpc.request_license_add( args )
424
+ success = got.xpath('add-success')[0]
425
+ return true if success
426
+ got.xpath('//message').text.strip
427
+ end
428
+
429
+ ## ----------------------------------------------------------------
430
+ ## remove a license
431
+ ##
432
+ ## license_id is the String license-id or the special name :all
433
+ ## ----------------------------------------------------------------
434
+
435
+ def license_rm!( license_id )
436
+ args = {}
437
+ if license_id == :all
438
+ args[:all] = true
439
+ else
440
+ args[:license_identifier] = license_id
441
+ end
442
+ got = @ndev.rpc.request_license_delete( args )
443
+ ### @@@ need to test return cases ... for now, just return
444
+ ### the 'got' XML
445
+ got
446
+ end
447
+
448
+ ## ----------------------------------------------------------------
449
+ ## save licenses (plr!) to a file
450
+ ## ----------------------------------------------------------------
451
+
452
+ def license_save( opts = {} )
453
+ raise StandardError, "not implemented yet"
454
+ end
455
+
456
+ end
457
+
458
+ ### -----------------------------------------------------------------
459
+ ### PRIVATE METHODS
460
+ ### -----------------------------------------------------------------
461
+
462
+ class Junos::Ez::RE::Provider
463
+ private
464
+
465
+ def _uptime_to_h( as_xml, up_h )
466
+ up_h[:time_now] = as_xml.xpath('current-time/date-time').text.strip
467
+
468
+ data = as_xml.xpath('uptime-information')[0]
469
+ up_h[:active_users] = data.xpath('active-user-count').text.to_i
470
+ up_h[:load_avg] = [
471
+ data.xpath('load-average-1').text.to_f,
472
+ data.xpath('load-average-5').text.to_f,
473
+ data.xpath('load-average-15').text.to_f,
474
+ ]
475
+ up_h[:uptime] = {
476
+ :at => data.xpath('date-time').text.strip,
477
+ :ago => data.xpath('up-time').text.strip,
478
+ }
479
+
480
+ data = as_xml.xpath('system-booted-time')[0]
481
+ up_h[:time_boot] = {
482
+ :at => data.xpath('date-time').text.strip,
483
+ :ago => data.xpath('time-length').text.strip
484
+ }
485
+
486
+ data = as_xml.xpath('protocols-started-time')[0]
487
+ up_h[:protocols_started] = {
488
+ :at => data.xpath('date-time').text.strip,
489
+ :ago => data.xpath('time-length').text.strip
490
+ }
491
+
492
+ data = as_xml.xpath('last-configured-time')[0]
493
+ up_h[:last_config] = {
494
+ :at => data.xpath('date-time').text.strip,
495
+ :ago => data.xpath('time-length').text.strip,
496
+ :by => data.xpath('user').text.strip
497
+ }
498
+ end
499
+
500
+ def _system_memory_to_h( as_xml, as_h )
501
+
502
+ summary = as_xml.xpath('system-memory-summary-information')[0]
503
+ as_h[:memory_summary] = {
504
+ :total => {
505
+ :size => summary.xpath('system-memory-total').text.to_i,
506
+ :percentage => summary.xpath('system-memory-total-percent').text.to_i
507
+ },
508
+ :reserved => {
509
+ :size => summary.xpath('system-memory-reserved').text.to_i,
510
+ :percentage => summary.xpath('system-memory-reserved-percent').text.to_i
511
+ },
512
+ :wired => {
513
+ :size => summary.xpath('system-memory-wired').text.to_i,
514
+ :percentage => summary.xpath('system-memory-wired-percent').text.to_i
515
+ },
516
+ :active => {
517
+ :size => summary.xpath('system-memory-active').text.to_i,
518
+ :percentage => summary.xpath('system-memory-active-percent').text.to_i
519
+ },
520
+ :inactive => {
521
+ :size => summary.xpath('system-memory-inactive').text.to_i,
522
+ :percentage => summary.xpath('system-memory-inactive-percent').text.to_i
523
+ },
524
+ :cache => {
525
+ :size => summary.xpath('system-memory-cache').text.to_i,
526
+ :percentage => summary.xpath('system-memory-cache-percent').text.to_i
527
+ },
528
+ :free => {
529
+ :size => summary.xpath('system-memory-free').text.to_i,
530
+ :percentage => summary.xpath('system-memory-free-percent').text.to_i
531
+ }
532
+ }
533
+
534
+ # create an Array of process information. The process-names are
535
+ # not guaranteed to be unique, so do this as an Array vs. Hash
536
+
537
+ as_h[:procs] = []
538
+ as_xml.xpath('pmap-terse-information/pmap-terse-summary').each do |proc|
539
+ proc_h = {}
540
+ as_h[:procs] << proc_h
541
+
542
+ proc_h[:name] = proc.xpath('map-name | process-name').text.strip
543
+ proc_h[:pid] = proc.xpath('pid').text.to_i
544
+ proc_h[:size] = proc.xpath('size').text.to_i
545
+ proc_h[:size_pct] = proc.xpath('size-percent').text.to_f
546
+ proc_h[:resident] = proc.xpath('resident').text.to_i
547
+ proc_h[:resident_pct] = proc.xpath('resident-percent').text.to_f
548
+ end
549
+
550
+ end
551
+
552
+ def _alarm_info_to_h( alarm, alarm_h )
553
+ alarm_h[:at] = alarm.xpath('alarm-time').text.strip
554
+ alarm_h[:class] = alarm.xpath('alarm-class').text.strip
555
+ alarm_h[:description] = alarm.xpath('alarm-description').text.strip
556
+ alarm_h[:type] = alarm.xpath('alarm-type').text.strip
557
+ end
558
+ end