shopify-junos-ez-stdlib 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +91 -0
- data/LICENSE +26 -0
- data/README.md +199 -0
- data/docs/Facts.md +192 -0
- data/docs/Providers/Group.md +61 -0
- data/docs/Providers/IPports.md +61 -0
- data/docs/Providers/L1ports.md +29 -0
- data/docs/Providers/L2ports.md +43 -0
- data/docs/Providers/LAGports.md +57 -0
- data/docs/Providers/StaticHosts.md +26 -0
- data/docs/Providers/StaticRoutes.md +37 -0
- data/docs/Providers/UserAuths.md +32 -0
- data/docs/Providers/Users.md +122 -0
- data/docs/Providers/Vlans.md +43 -0
- data/docs/Providers_Resources.md +353 -0
- data/docs/README_FIRST.md +27 -0
- data/docs/Utils/Config.md +160 -0
- data/docs/Utils/Filesystem.md +360 -0
- data/docs/Utils/Routing-Engine.md +379 -0
- data/docs/Utils/SCP.md +24 -0
- data/examples/config/config_file.rb +72 -0
- data/examples/config/config_template_object.rb +81 -0
- data/examples/config/config_template_simple.rb +76 -0
- data/examples/config/multi_config.rb +60 -0
- data/examples/fs_utils.rb +31 -0
- data/examples/lag_port.rb +27 -0
- data/examples/re_upgrade.rb +99 -0
- data/examples/re_utils.rb +33 -0
- data/examples/simple.rb +46 -0
- data/examples/st_hosts.rb +33 -0
- data/examples/user.rb +32 -0
- data/examples/vlans.rb +31 -0
- data/junos-ez-stdlib.gemspec +15 -0
- data/lib/junos-ez/exceptions.rb +3 -0
- data/lib/junos-ez/facts.rb +83 -0
- data/lib/junos-ez/facts/chassis.rb +51 -0
- data/lib/junos-ez/facts/ifd_style.rb +17 -0
- data/lib/junos-ez/facts/personality.rb +25 -0
- data/lib/junos-ez/facts/switch_style.rb +31 -0
- data/lib/junos-ez/facts/version.rb +58 -0
- data/lib/junos-ez/group.rb +206 -0
- data/lib/junos-ez/ip_ports.rb +30 -0
- data/lib/junos-ez/ip_ports/classic.rb +188 -0
- data/lib/junos-ez/l1_ports.rb +121 -0
- data/lib/junos-ez/l1_ports/classic.rb +87 -0
- data/lib/junos-ez/l1_ports/switch.rb +134 -0
- data/lib/junos-ez/l2_ports.rb +66 -0
- data/lib/junos-ez/l2_ports/bridge_domain.rb +499 -0
- data/lib/junos-ez/l2_ports/vlan.rb +433 -0
- data/lib/junos-ez/l2_ports/vlan_l2ng.rb +502 -0
- data/lib/junos-ez/lag_ports.rb +268 -0
- data/lib/junos-ez/provider.rb +619 -0
- data/lib/junos-ez/stdlib.rb +18 -0
- data/lib/junos-ez/system.rb +48 -0
- data/lib/junos-ez/system/st_hosts.rb +92 -0
- data/lib/junos-ez/system/st_routes.rb +159 -0
- data/lib/junos-ez/system/syscfg.rb +103 -0
- data/lib/junos-ez/system/userauths.rb +84 -0
- data/lib/junos-ez/system/users.rb +217 -0
- data/lib/junos-ez/utils/config.rb +236 -0
- data/lib/junos-ez/utils/fs.rb +385 -0
- data/lib/junos-ez/utils/re.rb +558 -0
- data/lib/junos-ez/version.rb +6 -0
- data/lib/junos-ez/vlans.rb +38 -0
- data/lib/junos-ez/vlans/bridge_domain.rb +89 -0
- data/lib/junos-ez/vlans/vlan.rb +119 -0
- data/lib/junos-ez/vlans/vlan_l2ng.rb +126 -0
- data/shipit.yml +4 -0
- data/tmp +7 -0
- 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
|