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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/README.md +58 -30
  4. data/Rakefile +7 -1
  5. data/code_lookups.yml +94 -0
  6. data/lib/boris.rb +17 -2
  7. data/lib/boris/connectors.rb +3 -2
  8. data/lib/boris/connectors/ssh.rb +92 -48
  9. data/lib/boris/connectors/wmi.rb +8 -5
  10. data/lib/boris/{helpers → core_ext}/array.rb +0 -0
  11. data/lib/boris/core_ext/datetime.rb +38 -0
  12. data/lib/boris/{helpers → core_ext}/hash.rb +0 -0
  13. data/lib/boris/{helpers → core_ext}/string.rb +91 -33
  14. data/lib/boris/{helpers → core_ext}/time.rb +0 -0
  15. data/lib/boris/helpers/constants.rb +6 -3
  16. data/lib/boris/helpers/scrubber.rb +2 -1
  17. data/lib/boris/options.rb +29 -7
  18. data/lib/boris/profiler_core.rb +15 -0
  19. data/lib/boris/profilers/big_ip/big_ip10.rb +10 -0
  20. data/lib/boris/profilers/big_ip/big_ip11.rb +10 -0
  21. data/lib/boris/profilers/big_ip_core.rb +210 -0
  22. data/lib/boris/profilers/brocade_fos/fos6.rb +10 -0
  23. data/lib/boris/profilers/brocade_fos_core.rb +144 -0
  24. data/lib/boris/profilers/cisco/ios12.rb +21 -0
  25. data/lib/boris/profilers/cisco/nxos5.rb +11 -0
  26. data/lib/boris/profilers/cisco_ios_core.rb +138 -0
  27. data/lib/boris/profilers/cisco_nxos_core.rb +148 -0
  28. data/lib/boris/profilers/linux/redhat/rhel5.rb +13 -0
  29. data/lib/boris/profilers/linux/redhat/rhel6.rb +13 -0
  30. data/lib/boris/profilers/linux/{redhat.rb → redhat_core.rb} +2 -8
  31. data/lib/boris/profilers/linux_core.rb +25 -7
  32. data/lib/boris/profilers/onboard_administrator/oa3.rb +10 -0
  33. data/lib/boris/profilers/onboard_administrator_core.rb +96 -0
  34. data/lib/boris/profilers/unix/solaris/solaris10.rb +11 -0
  35. data/lib/boris/profilers/unix/solaris/solaris11.rb +11 -0
  36. data/lib/boris/profilers/unix/{solaris.rb → solaris_core.rb} +13 -13
  37. data/lib/boris/profilers/unix_core.rb +23 -6
  38. data/lib/boris/profilers/windows/windows2003.rb +1 -2
  39. data/lib/boris/profilers/windows/windows2008.rb +1 -2
  40. data/lib/boris/profilers/windows/windows2012.rb +1 -2
  41. data/lib/boris/profilers/windows_core.rb +29 -8
  42. data/lib/boris/structure.rb +15 -0
  43. data/lib/boris/target.rb +19 -3
  44. data/lib/boris/version.rb +1 -1
  45. metadata +27 -11
  46. data/lib/boris/helpers.rb +0 -7
  47. data/lib/boris/profiler.rb +0 -18
@@ -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
- @failure_message = CONN_FAILURE_AUTH_FAILED
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
- @failure_message = CONN_FAILURE_RPC_FILTERED
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
- @failure_message = CONN_FAILURE_RPC_UNAVAILABLE
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
- @failure_message = message
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
- x = self.scan(/\((.*)\)/)
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
- x = self.scan(/["|'](.*?)["|']/).flatten
100
- x.empty? ? nil : x
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 [Nil, String] the formatted model, else returns self
150
+ # @return [String] the formatted model, else returns self
115
151
  def format_model
116
- return nil if self == ''
152
+ return self if self == ''
117
153
 
118
- # delete models containing "server" or beginning with "ibm"
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.scan(/\d/).join
157
+ 'SunBlade ' + model.extract(/(\d+)/)
125
158
  elsif model =~ /^sun.*fire/i
126
- 'SunFire ' + model.scan(/\d/).join
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
- 'Catalyst ' + (model.scan(/\d/).join + '-' + model.scan(/[a-z]$/i).join).sub(/-$/, '')
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.scan(/^.*[#{delimiter}](.*)$/)
239
- x.empty? ? nil : x.join.strip
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.scan(/^(.*?)[#{delimiter}]/)
251
- x.empty? ? nil : x.join.strip
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 Corp.'
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/helpers/string'
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'
@@ -1,7 +1,13 @@
1
- require 'boris/profiler'
2
-
3
- require 'boris/profilers/linux/redhat'
4
- require 'boris/profilers/unix/solaris'
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
- @options[:profilers] ||= [Profilers::RedHat, Profilers::Solaris]
43
- @options[:profilers].concat([Profilers::Windows2003, Profilers::Windows2008, Profilers::Windows2012]) if PLATFORM == :win32
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] << Profilers::Solaris
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,10 @@
1
+ require 'boris/profilers/big_ip_core'
2
+
3
+ module Boris; module Profilers
4
+ class BigIP10 < BigIPCore
5
+
6
+ def self.matches_target?(connector)
7
+ return true if connector.values_at('show sys version').join =~ /version 10/i
8
+ end
9
+ end
10
+ end; end
@@ -0,0 +1,10 @@
1
+ require 'boris/profilers/big_ip_core'
2
+
3
+ module Boris; module Profilers
4
+ class BigIP11 < BigIPCore
5
+
6
+ def self.matches_target?(connector)
7
+ return true if connector.values_at('show sys version').join =~ /version 11/i
8
+ end
9
+ end
10
+ 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