shopify-junos-ez-stdlib 1.0.0

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