boris 1.0.2 → 1.0.3
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 +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
|