boris 1.0.2 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/README.md +58 -30
- data/Rakefile +7 -1
- data/code_lookups.yml +94 -0
- data/lib/boris.rb +17 -2
- data/lib/boris/connectors.rb +3 -2
- data/lib/boris/connectors/ssh.rb +92 -48
- data/lib/boris/connectors/wmi.rb +8 -5
- data/lib/boris/{helpers → core_ext}/array.rb +0 -0
- data/lib/boris/core_ext/datetime.rb +38 -0
- data/lib/boris/{helpers → core_ext}/hash.rb +0 -0
- data/lib/boris/{helpers → core_ext}/string.rb +91 -33
- data/lib/boris/{helpers → core_ext}/time.rb +0 -0
- data/lib/boris/helpers/constants.rb +6 -3
- data/lib/boris/helpers/scrubber.rb +2 -1
- data/lib/boris/options.rb +29 -7
- data/lib/boris/profiler_core.rb +15 -0
- data/lib/boris/profilers/big_ip/big_ip10.rb +10 -0
- data/lib/boris/profilers/big_ip/big_ip11.rb +10 -0
- data/lib/boris/profilers/big_ip_core.rb +210 -0
- data/lib/boris/profilers/brocade_fos/fos6.rb +10 -0
- data/lib/boris/profilers/brocade_fos_core.rb +144 -0
- data/lib/boris/profilers/cisco/ios12.rb +21 -0
- data/lib/boris/profilers/cisco/nxos5.rb +11 -0
- data/lib/boris/profilers/cisco_ios_core.rb +138 -0
- data/lib/boris/profilers/cisco_nxos_core.rb +148 -0
- data/lib/boris/profilers/linux/redhat/rhel5.rb +13 -0
- data/lib/boris/profilers/linux/redhat/rhel6.rb +13 -0
- data/lib/boris/profilers/linux/{redhat.rb → redhat_core.rb} +2 -8
- data/lib/boris/profilers/linux_core.rb +25 -7
- data/lib/boris/profilers/onboard_administrator/oa3.rb +10 -0
- data/lib/boris/profilers/onboard_administrator_core.rb +96 -0
- data/lib/boris/profilers/unix/solaris/solaris10.rb +11 -0
- data/lib/boris/profilers/unix/solaris/solaris11.rb +11 -0
- data/lib/boris/profilers/unix/{solaris.rb → solaris_core.rb} +13 -13
- data/lib/boris/profilers/unix_core.rb +23 -6
- data/lib/boris/profilers/windows/windows2003.rb +1 -2
- data/lib/boris/profilers/windows/windows2008.rb +1 -2
- data/lib/boris/profilers/windows/windows2012.rb +1 -2
- data/lib/boris/profilers/windows_core.rb +29 -8
- data/lib/boris/structure.rb +15 -0
- data/lib/boris/target.rb +19 -3
- data/lib/boris/version.rb +1 -1
- metadata +27 -11
- data/lib/boris/helpers.rb +0 -7
- data/lib/boris/profiler.rb +0 -18
data/lib/boris/connectors/wmi.rb
CHANGED
@@ -59,15 +59,15 @@ module Boris
|
|
59
59
|
@connected = false
|
60
60
|
if error.message =~ /access is denied/i
|
61
61
|
warn "connection failed (connection made but credentials not accepted with user #{@user})"
|
62
|
-
@
|
62
|
+
@failure_messages << CONN_FAILURE_AUTH_FAILED
|
63
63
|
@reconnectable = true
|
64
64
|
elsif error.message =~ /call was canceled by the message filter/i
|
65
65
|
warn CONN_FAILURE_RPC_FILTERED
|
66
|
-
@
|
66
|
+
@failure_messages << CONN_FAILURE_RPC_FILTERED
|
67
67
|
@reconnectable = false
|
68
68
|
elsif error.message =~ /rpc server is unavailable/i
|
69
69
|
warn CONN_FAILURE_RPC_UNAVAILABLE
|
70
|
-
@
|
70
|
+
@failure_messages << CONN_FAILURE_RPC_UNAVAILABLE
|
71
71
|
@reconnectable = false
|
72
72
|
elsif error.message =~ /user credentials cannot be used for local connections/i
|
73
73
|
# clear the credentials then try to connect again
|
@@ -78,7 +78,7 @@ module Boris
|
|
78
78
|
else
|
79
79
|
message = "connection failed (#{error.message.gsub(/\n\s*/, '. ')})"
|
80
80
|
warn message
|
81
|
-
@
|
81
|
+
@failure_messages << message
|
82
82
|
@reconnectable = true
|
83
83
|
end
|
84
84
|
end
|
@@ -120,8 +120,11 @@ module Boris
|
|
120
120
|
rescue => error
|
121
121
|
if error.message =~ /access is denied/i
|
122
122
|
info "access denied on checking access on #{key_path}"
|
123
|
+
elsif error.message =~ /class not registered/i
|
124
|
+
info "error while checking access on #{key_path} (class not registered)"
|
125
|
+
info 'this could be caused by a lack of permissions or corrupted wmi installation'
|
123
126
|
else
|
124
|
-
info "error while checking access on #{key_path}"
|
127
|
+
info "error while checking access on #{key_path} (#{error.message})"
|
125
128
|
end
|
126
129
|
end
|
127
130
|
|
File without changes
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class DateTime
|
2
|
+
|
3
|
+
# Returns a new DateTime object showing the exact date and time that
|
4
|
+
# something occurred by using the difference in time between a date
|
5
|
+
# and the time that has elapsed. This is used to calculate the exact
|
6
|
+
# date and time that something occurred when we only know the current
|
7
|
+
# time and the time that elapsed since that event occurred.
|
8
|
+
#
|
9
|
+
# For example, in UNIX, we can't easily determine when a process was
|
10
|
+
# kicked off (by using data from the 'ps' command). But the 'ps' command
|
11
|
+
# will show us the time elapsed, so coupling that data with the current time,
|
12
|
+
# we can figure out when that process was started.
|
13
|
+
#
|
14
|
+
# now = DateTime.parse('2013-04-12T12:00:00-04:00')
|
15
|
+
# process_run_time = '1-05:59:59'
|
16
|
+
# DateTime.parse_start_date(now, process_run_time) #=> #<DateTime: 2013-04-11T10:00:01-04:00>
|
17
|
+
#
|
18
|
+
# @param base_time the base DateTime to calculate from (typically the current time)
|
19
|
+
# @param time_elapsed String showing the time elapsed (format: %d-%H:%M:%S)
|
20
|
+
# @return [DateTime] a new DateTime object showing the start date/time
|
21
|
+
def self.parse_start_date(base_time, time_elapsed)
|
22
|
+
time_elapsed = "0-#{time_elapsed}" unless time_elapsed =~ /-/
|
23
|
+
|
24
|
+
time_elapsed = time_elapsed.split('-')
|
25
|
+
days_back = time_elapsed[0].to_i
|
26
|
+
time_elapsed = time_elapsed[1].split(':')
|
27
|
+
|
28
|
+
hours_since = time_elapsed[0].to_i
|
29
|
+
minutes_since = time_elapsed[1].to_i
|
30
|
+
seconds_since = time_elapsed[2].to_i
|
31
|
+
|
32
|
+
seconds_since += minutes_since * 60
|
33
|
+
seconds_since += hours_since * 60 * 60
|
34
|
+
seconds_since += days_back * 60 * 60 * 24
|
35
|
+
|
36
|
+
started_on = (base_time.to_time - seconds_since).to_datetime
|
37
|
+
end
|
38
|
+
end
|
File without changes
|
@@ -79,14 +79,22 @@ class String
|
|
79
79
|
value_before_character('\\\\|\/')
|
80
80
|
end
|
81
81
|
|
82
|
+
# Returns the string value found between a pair of curly brackets from self.
|
83
|
+
#
|
84
|
+
# 'A{B}C'.between_curlies #=> "B"
|
85
|
+
#
|
86
|
+
# @return [Nil, String] string if value found, else returns nil
|
87
|
+
def between_curlies
|
88
|
+
self.extract(/\{(.*)\}/)
|
89
|
+
end
|
90
|
+
|
82
91
|
# Returns the string value found between a pair of parenthesis from self.
|
83
92
|
#
|
84
93
|
# 'A(B)C'.between_parenthesis #=> "B"
|
85
94
|
#
|
86
95
|
# @return [Nil, String] string if value found, else returns nil
|
87
96
|
def between_parenthesis
|
88
|
-
|
89
|
-
x.empty? ? nil : x.join
|
97
|
+
self.extract(/\((.*)\)/)
|
90
98
|
end
|
91
99
|
|
92
100
|
# Returns the string value found between a pair of quotes (single or double)
|
@@ -96,8 +104,36 @@ class String
|
|
96
104
|
#
|
97
105
|
# @return [Nil, String] string if value found, else returns nil
|
98
106
|
def between_quotes
|
99
|
-
|
100
|
-
|
107
|
+
self.extract(/["|'](.*?)["|']/)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Cleans self by stripping leading/trailing spaces, any consecutive spaces, and
|
111
|
+
# removing any ASCII characters that are sometimes reported by devices. Also
|
112
|
+
# removes registered (R) characters.
|
113
|
+
#
|
114
|
+
# 'Microsoft(R) Windows(R)'.clean_string #=> "Microsoft Windows"
|
115
|
+
# "string with\u00A0 weird character".clean_string #=> "string with weird character"
|
116
|
+
#
|
117
|
+
# @return [String] the cleaned up string
|
118
|
+
def clean_string
|
119
|
+
# remove registered "(R)" and trademark "(tm)" marks
|
120
|
+
string = self.gsub(/\(r\)|\(tm\)/i, '')
|
121
|
+
string.gsub!(/\s+/, ' ')
|
122
|
+
|
123
|
+
string.encode(Encoding.find('ASCII'), :undef=>:replace, :replace=>'').strip
|
124
|
+
end
|
125
|
+
|
126
|
+
# Attempts to pull only the first match inside the parenthesis for a given
|
127
|
+
# regex. It's similar to using String#match or String#scan..join to extract
|
128
|
+
# the first matching value (that is, the value to match on found within the
|
129
|
+
# parenthesis in the regex).
|
130
|
+
#
|
131
|
+
# 'abcdef'.extract(/ab(cd)ef/) #=> "cd"
|
132
|
+
# 'abcdef'.extract(/abcdef/) #=> nil
|
133
|
+
#
|
134
|
+
# @return [String, NilClass] the matched string, else returns nil
|
135
|
+
def extract(regex)
|
136
|
+
self[regex, 1]
|
101
137
|
end
|
102
138
|
|
103
139
|
# Attempts to grab the hardware model from self and formats it for
|
@@ -111,25 +147,23 @@ class String
|
|
111
147
|
# 'sun fire 400'.format_model #=> "SunFire 400"
|
112
148
|
# 't1000'.format_model #=> "SPARC Enterprise T1000"
|
113
149
|
#
|
114
|
-
# @return [
|
150
|
+
# @return [String] the formatted model, else returns self
|
115
151
|
def format_model
|
116
|
-
return
|
152
|
+
return self if self == ''
|
117
153
|
|
118
|
-
|
119
|
-
# also remove configuration numbers appended (typically on IBM
|
120
|
-
# products... ex 'System x1000 M3 -[123456]-')
|
121
|
-
model = self.gsub(/(^ibm|server)/i, '').split(/-*(\[|\()/)[0]
|
154
|
+
model = self.sub(/server/i, '')
|
122
155
|
|
123
156
|
model = if model =~ /^sun.*blade/i
|
124
|
-
'SunBlade ' + model.
|
157
|
+
'SunBlade ' + model.extract(/(\d+)/)
|
125
158
|
elsif model =~ /^sun.*fire/i
|
126
|
-
'SunFire ' + model.
|
159
|
+
'SunFire ' + model.extract(/(\d+)/)
|
127
160
|
elsif model =~ /^T\d{4}/
|
128
161
|
'SPARC Enterprise ' + model
|
129
162
|
elsif model =~ /^big-*ip/i
|
130
163
|
model.sub(/^big-*ip/i, 'BIG-IP')
|
131
164
|
elsif model =~ /^wsc\d{4}-*.*/i
|
132
|
-
|
165
|
+
model.sub!(/wsc/i, 'Catalyst ')
|
166
|
+
model.include?('-') ? model : model.sub(/(\d{4})(.*)/) {$2.empty? ? "#{$1}" : "#{$1}-#{$2}" }
|
133
167
|
else
|
134
168
|
model
|
135
169
|
end
|
@@ -194,6 +228,44 @@ class String
|
|
194
228
|
def hex_to_ip_address
|
195
229
|
self.scan(/../).map {|octet| octet.hex}.join('.')
|
196
230
|
end
|
231
|
+
|
232
|
+
# Pads self with leading zeros if needed. Useful for properly formatting a String
|
233
|
+
# (usually from the ps command in UNIX representing elapsed time) to a more complete,
|
234
|
+
# zero-padded string to the format dd-hh:mm:ss. mm::ss is the bare-minimum required
|
235
|
+
# String.
|
236
|
+
#
|
237
|
+
# '00:01'.pad_elapsed_time #=> '00-00:00:01'
|
238
|
+
# '01:01'.pad_elapsed_time #=> '00-00:01:01'
|
239
|
+
# '01:01:01'.pad_elapsed_time #=> '00-01:01:01'
|
240
|
+
# '1-01:00:01'.pad_elapsed_time #=> '01-01:01:01'
|
241
|
+
#
|
242
|
+
# @return String the padded elapsed time
|
243
|
+
def pad_elapsed_time
|
244
|
+
return self if self =~ /\d{2}\-\d{2}:\d{2}:\d{2}/
|
245
|
+
|
246
|
+
return "0#{self}" if self =~ /\d{1}-/
|
247
|
+
|
248
|
+
case self.count(':')
|
249
|
+
when 2; "00-#{self}"
|
250
|
+
when 1; "00-00:#{self}"
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
# Pads self with leading zeros if needed. Useful for properly formatting MAC addresses.
|
255
|
+
# Takes an optional delimiter used for splitting and returning the provided string in
|
256
|
+
# the proper format. The string to be formatted is expected to already be in a six-octet
|
257
|
+
# format.
|
258
|
+
#
|
259
|
+
# '0:0:0:0:0:AA'.pad_mac_address #=> "00:00:00:00:00:AA"
|
260
|
+
# '0-0-0-0-AA-12'.pad_mac_address('-') #=> "00-00-00-00-AA-12"
|
261
|
+
#
|
262
|
+
# @param delimiter an optional delimiter for the MAC address (default is ':')
|
263
|
+
# @return [String] the padded MAC address
|
264
|
+
def pad_mac_address(delimiter=':')
|
265
|
+
self.split(delimiter).inject([]) do |mac, octet|
|
266
|
+
octet.length == 1 ? mac << "0#{octet}" : mac << octet
|
267
|
+
end.join(delimiter).upcase
|
268
|
+
end
|
197
269
|
|
198
270
|
# Returns a new string with the architecture removed. See {String#remove_arch!}.
|
199
271
|
#
|
@@ -211,32 +283,17 @@ class String
|
|
211
283
|
self.replace(self.gsub(/\s+\(*(32|64)(-|\s)*bit\)*/, ''))
|
212
284
|
end
|
213
285
|
|
214
|
-
# Cleans self by stripping leading/trailing spaces, and removing any ASCII
|
215
|
-
# characters that are sometimes reported by devices. Also removes registered
|
216
|
-
# (R) characters.
|
217
|
-
#
|
218
|
-
# 'Microsoft(R) Windows(R)'.clean_string #=> "Microsoft Windows"
|
219
|
-
# "string with\u00A0 weird characters".clean_string #=> "string with weird characters"
|
220
|
-
#
|
221
|
-
# @return [String] the cleaned up string
|
222
|
-
def clean_string
|
223
|
-
# remove registered "(R)" and trademark "(tm)" marks
|
224
|
-
string = self.gsub(/\(r\)|\(tm\)/i, '')
|
225
|
-
string.gsub!(/\s+/, ' ')
|
226
|
-
|
227
|
-
string.encode(Encoding.find('ASCII'), :undef=>:replace, :replace=>'').strip
|
228
|
-
end
|
229
|
-
|
230
286
|
# Allows you to specify your own delimiter to grab the string value found
|
231
287
|
# after the last delimiter. It's mainly used internally with the
|
232
288
|
# #after_ helper methods.
|
233
289
|
#
|
234
290
|
# 'A&B&C'.value_after_character('&') #=> "C"
|
235
291
|
#
|
292
|
+
# @param delimiter
|
236
293
|
# @return [Nil, String] returns the found value, else returns nil
|
237
294
|
def value_after_character(delimiter)
|
238
|
-
x = self.
|
239
|
-
x.
|
295
|
+
x = self.extract(/^.*[#{delimiter}](.*)$/)
|
296
|
+
x.nil? ? nil : x.strip
|
240
297
|
end
|
241
298
|
|
242
299
|
# Allows you to specify your own delimiter to grab the string value found
|
@@ -245,9 +302,10 @@ class String
|
|
245
302
|
#
|
246
303
|
# 'A&B&C'.value_before_character('&') #=> "A"
|
247
304
|
#
|
305
|
+
# @param delimiter
|
248
306
|
# @return [Nil, String] returns the found value, else returns nil
|
249
307
|
def value_before_character(delimiter)
|
250
|
-
x = self.
|
251
|
-
x.
|
308
|
+
x = self.extract(/(.*?)[#{delimiter}]/)
|
309
|
+
x.nil? ? nil : x.strip
|
252
310
|
end
|
253
311
|
end
|
File without changes
|
@@ -2,10 +2,10 @@ module Boris
|
|
2
2
|
VENDOR_ADOBE = 'Adobe Systems, Inc.'
|
3
3
|
VENDOR_AMD = 'AMD, Inc.'
|
4
4
|
VENDOR_APC = 'APC Corp.'
|
5
|
-
VENDOR_BROCADE = 'Brocade Communications
|
5
|
+
VENDOR_BROCADE = 'Brocade Communications, Inc.'
|
6
6
|
VENDOR_CISCO = 'Cisco Systems, Inc.'
|
7
7
|
VENDOR_CITRIX = 'Citrix Systems, Inc.'
|
8
|
-
VENDOR_DELL = 'Dell Inc.'
|
8
|
+
VENDOR_DELL = 'Dell, Inc.'
|
9
9
|
VENDOR_EMULEX = 'Emulex Corp.'
|
10
10
|
VENDOR_F5 = 'F5 Networks, Inc.'
|
11
11
|
VENDOR_HP = 'Hewlett Packard, Inc.'
|
@@ -14,7 +14,7 @@ module Boris
|
|
14
14
|
VENDOR_MICROSOFT = 'Microsoft Corp.'
|
15
15
|
VENDOR_ORACLE = 'Oracle Corp.'
|
16
16
|
VENDOR_QLOGIC = 'QLogic Corp.'
|
17
|
-
VENDOR_REDHAT = 'Red Hat Inc.'
|
17
|
+
VENDOR_REDHAT = 'Red Hat, Inc.'
|
18
18
|
VENDOR_SUSE = 'SUSE Linux GmbH'
|
19
19
|
VENDOR_VMWARE = 'VMware, Inc.'
|
20
20
|
|
@@ -28,5 +28,8 @@ module Boris
|
|
28
28
|
CONN_FAILURE_RPC_UNAVAILABLE = 'connection failed (wmi: rpc server unavailable)'
|
29
29
|
CONN_FAILURE_LOCAL_CREDENTIALS = 'connection failed (wmi: credentials used locally, will try again)'
|
30
30
|
CONN_FAILURE_PASSWORD_EXPIRED = 'connection failed (password expired, requires changing)'
|
31
|
+
CONN_FAILURE_REFUSED = 'connection failed (target actively refused the connection)'
|
32
|
+
CONN_FAILURE_CONNECTION_CLOSED = 'connection failed (connection closed by remote host)'
|
31
33
|
|
34
|
+
CODE_LOOKUPS = YAML::load(File.open(File.join(LIB_PATH, '..', 'code_lookups.yml')))
|
32
35
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'boris/
|
1
|
+
require 'boris/core_ext/string'
|
2
2
|
|
3
3
|
module Boris
|
4
4
|
module Structure
|
@@ -36,6 +36,7 @@ module Boris
|
|
36
36
|
interface[:node_wwn].downcase! unless !interface[:node_wwn]
|
37
37
|
interface[:port_wwn].downcase! unless !interface[:port_wwn]
|
38
38
|
interface[:remote_mac_address].upcase! unless !interface[:remote_mac_address]
|
39
|
+
interface[:remote_wwn].upcase! unless !interface[:remote_wwn]
|
39
40
|
interface[:vendor] = interface[:vendor].format_vendor unless !interface[:vendor]
|
40
41
|
end if @network_interfaces
|
41
42
|
debug 'network interface data cleaned up'
|
data/lib/boris/options.rb
CHANGED
@@ -1,7 +1,13 @@
|
|
1
|
-
require 'boris/
|
2
|
-
|
3
|
-
require 'boris/profilers/
|
4
|
-
require 'boris/profilers/
|
1
|
+
require 'boris/profilers/big_ip/big_ip10'
|
2
|
+
require 'boris/profilers/big_ip/big_ip11'
|
3
|
+
require 'boris/profilers/brocade_fos/fos6'
|
4
|
+
require 'boris/profilers/cisco/ios12'
|
5
|
+
require 'boris/profilers/cisco/nxos5'
|
6
|
+
require 'boris/profilers/linux/redhat/rhel5'
|
7
|
+
require 'boris/profilers/linux/redhat/rhel6'
|
8
|
+
require 'boris/profilers/onboard_administrator/oa3'
|
9
|
+
require 'boris/profilers/unix/solaris/solaris10'
|
10
|
+
require 'boris/profilers/unix/solaris/solaris11'
|
5
11
|
require 'boris/profilers/windows/windows2003'
|
6
12
|
require 'boris/profilers/windows/windows2008'
|
7
13
|
require 'boris/profilers/windows/windows2012'
|
@@ -39,8 +45,24 @@ module Boris
|
|
39
45
|
# set our defaults
|
40
46
|
@options[:auto_scrub_data] ||= true
|
41
47
|
@options[:credentials] ||= []
|
42
|
-
|
43
|
-
|
48
|
+
if !@options[:profilers]
|
49
|
+
|
50
|
+
@options[:profilers] = [
|
51
|
+
Profilers::RHEL5,
|
52
|
+
Profilers::RHEL6,
|
53
|
+
Profilers::Solaris10,
|
54
|
+
Profilers::Solaris11
|
55
|
+
]
|
56
|
+
|
57
|
+
if PLATFORM == :win32
|
58
|
+
@options[:profilers].concat([
|
59
|
+
Profilers::Windows2003,
|
60
|
+
Profilers::Windows2008,
|
61
|
+
Profilers::Windows2012
|
62
|
+
])
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
44
66
|
@options[:snmp_options] ||= {}
|
45
67
|
@options[:ssh_options] ||= {}
|
46
68
|
|
@@ -64,7 +86,7 @@ module Boris
|
|
64
86
|
|
65
87
|
# Setter method for setting the value in the options hash
|
66
88
|
# puts options[:profilers] #=> [Profilers::RedHat]
|
67
|
-
# options[:profilers] <<
|
89
|
+
# options[:profilers] << Bases::Solaris
|
68
90
|
# puts options[:profilers] #=> [Profilers::RedHat, Profilers::Solaris]
|
69
91
|
# @raise ArgumentError when invalid options are provided
|
70
92
|
def []=(key, val)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'boris/structure'
|
2
|
+
|
3
|
+
module Boris; module ProfilerCore
|
4
|
+
include Lumberjack
|
5
|
+
include Structure
|
6
|
+
|
7
|
+
attr_reader :cache
|
8
|
+
|
9
|
+
def initialize(connector)
|
10
|
+
@host = connector.host
|
11
|
+
@logger = Boris.logger
|
12
|
+
@connector = connector
|
13
|
+
@cache = {:users=>[]}
|
14
|
+
end
|
15
|
+
end; end
|
@@ -0,0 +1,210 @@
|
|
1
|
+
require 'boris/profiler_core'
|
2
|
+
|
3
|
+
module Boris; module Profilers
|
4
|
+
class BigIPCore
|
5
|
+
include ProfilerCore
|
6
|
+
|
7
|
+
attr_reader :license_data, :os_data
|
8
|
+
|
9
|
+
def self.connection_type
|
10
|
+
Boris::SSHConnector
|
11
|
+
end
|
12
|
+
|
13
|
+
def license_data
|
14
|
+
@license_data ||= @connector.values_at('show sys license')
|
15
|
+
end
|
16
|
+
|
17
|
+
def os_data
|
18
|
+
@os_data ||= @connector.values_at('show sys version')
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_file_systems; super; end
|
22
|
+
|
23
|
+
def get_hardware
|
24
|
+
super
|
25
|
+
|
26
|
+
hardware_data = @connector.values_at('show sys hardware').join("\n").split(/\n\s*\n/)
|
27
|
+
cpu_mem_data = @connector.values_at('show sys host').join("\n").split(/\n\s*\n/)
|
28
|
+
|
29
|
+
cpu_data = hardware_data.grep(/name\s+cpus/i)[0].split(/\n/)
|
30
|
+
platform_data = hardware_data.grep(/platform/i)[0].split(/\n/)
|
31
|
+
mem_data = cpu_mem_data.grep(/memory \(bytes\)/i)[0].split(/\n/)
|
32
|
+
|
33
|
+
@hardware[:cpu_core_count] = cpu_data.grep(/\s{2,}cores/i)[0].split(/\s+/)[2].to_i
|
34
|
+
@hardware[:cpu_model] = cpu_data.grep(/model/i)[0].split(/\s{2,}/).last
|
35
|
+
@hardware[:cpu_physical_count] = cpu_mem_data.grep(/\s{2,}cpu count/i)[0].split.last.to_i
|
36
|
+
@hardware[:cpu_speed_mhz] = cpu_data.grep(/cpu mhz/i)[0].split.last.to_i
|
37
|
+
firmware = platform_data.grep(/bios revision/i)[0].split(/\s{2,}/).last
|
38
|
+
@hardware[:firmware_version] = firmware =~ /bios|ver\:/i ? firmware.split(/bios|ver\:/i).last : firmware
|
39
|
+
@hardware[:model] = platform_data.grep(/name/i)[0].split(/\s{2,}/).last + " (#{license_data.grep(/platform id/i)[0].split.last})"
|
40
|
+
|
41
|
+
memory = mem_data.grep(/total/i)[0].split.last
|
42
|
+
@hardware[:memory_installed_mb] = if memory =~ /g$/i
|
43
|
+
(memory.sub('g', '').to_f * 1024).to_i
|
44
|
+
elsif memory =~ /m$/i
|
45
|
+
memory.sub('m', '').to_f
|
46
|
+
end
|
47
|
+
|
48
|
+
@hardware[:serial] = hardware_data.grep(/system information/i)[0].split(/\n/).grep(/chassis serial/i)[0].split.last
|
49
|
+
|
50
|
+
@hardware[:vendor] = VENDOR_F5
|
51
|
+
|
52
|
+
@hardware
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_hosted_shares; super; end
|
56
|
+
|
57
|
+
def get_installed_applications
|
58
|
+
super
|
59
|
+
|
60
|
+
license_data.grep(/.*\(.*\)/).each do |application|
|
61
|
+
h = installed_application_template
|
62
|
+
|
63
|
+
h[:license_key] = application.between_parenthesis
|
64
|
+
h[:name] = application.split('(')[0].strip
|
65
|
+
h[:vendor] = VENDOR_F5
|
66
|
+
|
67
|
+
@installed_applications << h
|
68
|
+
end
|
69
|
+
|
70
|
+
@installed_applications
|
71
|
+
end
|
72
|
+
|
73
|
+
def get_installed_patches
|
74
|
+
super
|
75
|
+
|
76
|
+
patch_data = os_data.join("\n")
|
77
|
+
|
78
|
+
if patch_data =~ /hotfix list/i
|
79
|
+
patch_data.split(/hotfix list/i).last.scan(/\w+/).each do |patch|
|
80
|
+
@installed_patches << {:date_installed=>nil, :installed_by=>nil, :patch_code=>patch}
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
@installed_patches
|
85
|
+
end
|
86
|
+
|
87
|
+
def get_installed_services; super; end
|
88
|
+
def get_local_user_groups; super; end
|
89
|
+
|
90
|
+
def get_network_id
|
91
|
+
super
|
92
|
+
|
93
|
+
hostname = @connector.values_at('list sys global-settings hostname').grep(/hostname/)[0].split.last.split('.')
|
94
|
+
|
95
|
+
@network_id[:hostname] = hostname.shift
|
96
|
+
@network_id[:domain] = hostname.join('.') if hostname.any?
|
97
|
+
|
98
|
+
@network_id
|
99
|
+
end
|
100
|
+
|
101
|
+
def get_network_interfaces
|
102
|
+
super
|
103
|
+
|
104
|
+
dns_servers = @connector.values_at('list sys dns').grep(/servers/)[0].between_curlies.strip.split
|
105
|
+
|
106
|
+
interfaces = []
|
107
|
+
@connector.values_at('list net interface all-properties').join("\n").split(/\}/).each do |interface|
|
108
|
+
interface = interface.strip.split(/\n/)
|
109
|
+
h = network_interface_template
|
110
|
+
|
111
|
+
h[:mac_address] = interface.grep(/mac\-address/)[0].split.last.pad_mac_address
|
112
|
+
h[:model] = 'Unknown Ethernet Adapter'
|
113
|
+
h[:name] = interface[0].split[2]
|
114
|
+
|
115
|
+
interfaces << h
|
116
|
+
end
|
117
|
+
|
118
|
+
interface_properties = @connector.values_at('show net interface all-properties field-fmt').grep(/\{|\}|media|status|trunk/)
|
119
|
+
interface_properties = interface_properties.join("\n").split(/^\s*net/)
|
120
|
+
|
121
|
+
vlans = @connector.values_at('list net vlan').grep(/\{|\}/)
|
122
|
+
vlans = vlans.join("\n").split(/^\s*net/)
|
123
|
+
|
124
|
+
self_ips = @connector.values_at('show running-config net self all-properties').grep(/\{|vlan|address|\}/)
|
125
|
+
self_ips = self_ips.join("\n").split(/^\s*net/)
|
126
|
+
|
127
|
+
interfaces.each do |h|
|
128
|
+
|
129
|
+
next if h[:mac_address] =~ /none/i
|
130
|
+
|
131
|
+
properties = interface_properties.grep(/interface #{h[:name]} \{/).join.split(/\n/)
|
132
|
+
|
133
|
+
h[:status] = properties.grep(/status/i)[0].split.last
|
134
|
+
h[:status] = 'down' unless h[:status] == 'up'
|
135
|
+
|
136
|
+
media = properties.grep(/media\-active/i)[0].split.last
|
137
|
+
media = nil if media =~ /none/i
|
138
|
+
|
139
|
+
h[:type] = 'ethernet'
|
140
|
+
h[:vendor] = VENDOR_F5
|
141
|
+
|
142
|
+
if h[:status] == 'up'
|
143
|
+
h[:current_speed_mbps] = media.scan(/\d+/)[0].to_i
|
144
|
+
h[:dns_servers] = dns_servers
|
145
|
+
h[:duplex] = case
|
146
|
+
when media =~ /fd$/i
|
147
|
+
'full'
|
148
|
+
when media =~ /hd$/i
|
149
|
+
'half'
|
150
|
+
end
|
151
|
+
|
152
|
+
#h[:mtu] = properties.grep(/mtu/i)[0].split.last.to_i
|
153
|
+
|
154
|
+
trunk = properties.grep(/trunk\-name/i)[0].split.last
|
155
|
+
trunk = nil if trunk =~ /none/i
|
156
|
+
|
157
|
+
bound_vlans = []
|
158
|
+
|
159
|
+
[h[:name], trunk].each do |interface_name|
|
160
|
+
matched_vlans = vlans.grep(/ #{interface_name} \{/)
|
161
|
+
|
162
|
+
matched_vlans.each do |matched_vlan|
|
163
|
+
bound_vlans << matched_vlan.split[1]
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
bound_vlans.each do |bound_vlan|
|
168
|
+
bound_ips = self_ips.grep(/vlan #{bound_vlan}/)
|
169
|
+
|
170
|
+
bound_ips.each do |bound_ip|
|
171
|
+
bound_ip = bound_ip.split(/\n/)
|
172
|
+
|
173
|
+
# bigip version 10 reports ip address as first line, where
|
174
|
+
# version 11 reports ip on its own line with bitmask attached
|
175
|
+
ip_data = if bound_ip[1] =~ /address/i #aka version 11
|
176
|
+
bound_ip.grep(/address/)[0].split.last
|
177
|
+
else #aka version 10
|
178
|
+
bound_ip.grep(/self/)[0].split[1]
|
179
|
+
end
|
180
|
+
|
181
|
+
ip_data = ip_data.split(/\//)
|
182
|
+
|
183
|
+
ip_address = ip_data.first
|
184
|
+
subnet = NetAddr.i_to_ip(NetAddr.bits_to_mask(ip_data.last.to_i, NetAddr::CIDRv4))
|
185
|
+
|
186
|
+
h[:ip_addresses] << {:ip_address=>ip_address, :subnet=>subnet}
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
@network_interfaces << h
|
192
|
+
end
|
193
|
+
|
194
|
+
@network_interfaces
|
195
|
+
end
|
196
|
+
|
197
|
+
def get_operating_system
|
198
|
+
super
|
199
|
+
|
200
|
+
@operating_system[:kernel] = os_data.grep(/build/i)[0].split.last
|
201
|
+
@operating_system[:license_key] = license_data.grep(/registration key/i)[0].split.last
|
202
|
+
@operating_system[:name] = os_data.grep(/product/i)[0].split.last
|
203
|
+
@operating_system[:service_pack] = os_data.grep(/edition/i)[0].split(/\s{2,}/).last
|
204
|
+
@operating_system[:version] = os_data.grep(/version\s+/i)[0].split.last
|
205
|
+
|
206
|
+
@operating_system
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
210
|
+
end; end
|