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