boris 1.0.0.beta.1

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 (88) hide show
  1. data/LICENSE.md +9 -0
  2. data/README.md +94 -0
  3. data/boris.gemspec +28 -0
  4. data/doc/Array.html +437 -0
  5. data/doc/Boris.html +230 -0
  6. data/doc/Boris/ConnectionAlreadyActive.html +123 -0
  7. data/doc/Boris/ConnectionFailed.html +127 -0
  8. data/doc/Boris/Connector.html +794 -0
  9. data/doc/Boris/InvalidCredentials.html +131 -0
  10. data/doc/Boris/InvalidOption.html +123 -0
  11. data/doc/Boris/InvalidTargetName.html +123 -0
  12. data/doc/Boris/Lumberjack.html +466 -0
  13. data/doc/Boris/MissingCredentials.html +123 -0
  14. data/doc/Boris/NoActiveConnection.html +123 -0
  15. data/doc/Boris/NoProfileDetected.html +123 -0
  16. data/doc/Boris/Options.html +783 -0
  17. data/doc/Boris/Profiles.html +117 -0
  18. data/doc/Boris/Profiles/Linux.html +1151 -0
  19. data/doc/Boris/Profiles/RedHat.html +875 -0
  20. data/doc/Boris/Profiles/Solaris.html +1230 -0
  21. data/doc/Boris/Profiles/Structure.html +2050 -0
  22. data/doc/Boris/Profiles/UNIX.html +893 -0
  23. data/doc/Boris/Profiles/Windows.html +1846 -0
  24. data/doc/Boris/Profiles/Windows/Windows2003.html +304 -0
  25. data/doc/Boris/Profiles/Windows/Windows2008.html +379 -0
  26. data/doc/Boris/Profiles/Windows/Windows2012.html +304 -0
  27. data/doc/Boris/SNMPConnector.html +512 -0
  28. data/doc/Boris/SSHConnector.html +633 -0
  29. data/doc/Boris/Target.html +2002 -0
  30. data/doc/Boris/WMIConnector.html +1134 -0
  31. data/doc/BorisLogger.html +217 -0
  32. data/doc/Hash.html +195 -0
  33. data/doc/String.html +1246 -0
  34. data/doc/_index.html +420 -0
  35. data/doc/class_list.html +53 -0
  36. data/doc/css/common.css +1 -0
  37. data/doc/css/full_list.css +57 -0
  38. data/doc/css/style.css +328 -0
  39. data/doc/file.README.html +183 -0
  40. data/doc/file_list.html +55 -0
  41. data/doc/frames.html +28 -0
  42. data/doc/index.html +183 -0
  43. data/doc/js/app.js +214 -0
  44. data/doc/js/full_list.js +173 -0
  45. data/doc/js/jquery.js +4 -0
  46. data/doc/method_list.html +1468 -0
  47. data/doc/top-level-namespace.html +126 -0
  48. data/lib/boris.rb +30 -0
  49. data/lib/boris/connectors.rb +47 -0
  50. data/lib/boris/connectors/snmp.rb +56 -0
  51. data/lib/boris/connectors/ssh.rb +110 -0
  52. data/lib/boris/connectors/wmi.rb +186 -0
  53. data/lib/boris/errors.rb +17 -0
  54. data/lib/boris/helpers/array.rb +63 -0
  55. data/lib/boris/helpers/constants.rb +20 -0
  56. data/lib/boris/helpers/hash.rb +8 -0
  57. data/lib/boris/helpers/scrubber.rb +51 -0
  58. data/lib/boris/helpers/string.rb +130 -0
  59. data/lib/boris/lumberjack.rb +47 -0
  60. data/lib/boris/options.rb +86 -0
  61. data/lib/boris/profiles/linux/redhat.rb +77 -0
  62. data/lib/boris/profiles/linux_core.rb +216 -0
  63. data/lib/boris/profiles/unix/solaris.rb +307 -0
  64. data/lib/boris/profiles/unix_core.rb +85 -0
  65. data/lib/boris/profiles/windows/windows2003.rb +15 -0
  66. data/lib/boris/profiles/windows/windows2008.rb +23 -0
  67. data/lib/boris/profiles/windows/windows2012.rb +15 -0
  68. data/lib/boris/profiles/windows_core.rb +530 -0
  69. data/lib/boris/structure.rb +167 -0
  70. data/lib/boris/target.rb +340 -0
  71. data/test/connector_tests/test_snmp.rb +35 -0
  72. data/test/connector_tests/test_ssh.rb +51 -0
  73. data/test/connector_tests/test_wmi.rb +129 -0
  74. data/test/helper_tests/test_array.rb +25 -0
  75. data/test/helper_tests/test_hash.rb +10 -0
  76. data/test/helper_tests/test_string.rb +136 -0
  77. data/test/profile_tests/test_core_skeleton +107 -0
  78. data/test/profile_tests/test_linux_core.rb +331 -0
  79. data/test/profile_tests/test_redhat.rb +134 -0
  80. data/test/profile_tests/test_solaris.rb +523 -0
  81. data/test/profile_tests/test_unix_core.rb +117 -0
  82. data/test/profile_tests/test_windows.rb +536 -0
  83. data/test/setup_tests.rb +14 -0
  84. data/test/test_all.rb +8 -0
  85. data/test/test_options.rb +44 -0
  86. data/test/test_structure.rb +136 -0
  87. data/test/test_target.rb +146 -0
  88. metadata +241 -0
@@ -0,0 +1,17 @@
1
+ module Boris
2
+ class MissingCredentials < Exception; end
3
+
4
+ class ConnectionFailed < StandardError; end
5
+
6
+ class ConnectionAlreadyActive < StandardError; end
7
+
8
+ class NoActiveConnection < StandardError; end
9
+
10
+ class NoProfileDetected < StandardError; end
11
+
12
+ class InvalidOption < StandardError; end
13
+
14
+ class InvalidCredentials < ConnectionFailed; end
15
+
16
+ class InvalidTargetName < StandardError; end
17
+ end
@@ -0,0 +1,63 @@
1
+ class Array
2
+ def strip_string_values_in_array
3
+ self.map! do |val|
4
+ val.strip_string_values_in_array if val.is_a?(Array)
5
+ val.strip_string_values_in_hash if val.is_a?(Hash)
6
+ val.is_a?(String) ? val.strip : val
7
+ end
8
+ end
9
+
10
+ def to_ms_product_key
11
+ valid_chars = 'BCDFGHJKMPQRTVWXY2346789'.scan(/./)
12
+
13
+ product_key = nil
14
+
15
+ raw_product_key = []
16
+
17
+ 52.upto(66) do |idx|
18
+ raw_product_key << self[idx]
19
+ end
20
+
21
+ 24.downto(0) do |a|
22
+ b = 0
23
+
24
+ 14.downto(0) do |c|
25
+ b = b * 256 ^ raw_product_key[c]
26
+ raw_product_key[c] = (b / 24).to_i
27
+ b = b.remainder(24)
28
+ end
29
+
30
+ product_key = "#{valid_chars[b]}#{product_key}"
31
+
32
+ if a.remainder(5) == 0 && a != 0
33
+ product_key = "-#{product_key}"
34
+ end
35
+ end
36
+
37
+ return product_key.upcase
38
+ end
39
+
40
+ def to_nil_hash
41
+ h = Hash.new
42
+ self.each do |item|
43
+ if item.kind_of?(Hash)
44
+ h.merge!(item)
45
+ else
46
+ h[item.to_sym] = nil
47
+ end
48
+ end
49
+ return h
50
+ end
51
+
52
+ def to_wwn
53
+ wwn = []
54
+
55
+ 0.upto(7) do |i|
56
+ hex = self[i].to_s(16)
57
+ hex = "0#{hex}" if self[i] < 16
58
+ wwn << hex
59
+ end
60
+
61
+ return wwn.join
62
+ end
63
+ end
@@ -0,0 +1,20 @@
1
+ module Boris
2
+ VENDOR_ADOBE = 'Adobe Systems, Inc.'
3
+ VENDOR_AMD = 'AMD, Inc.'
4
+ VENDOR_APC = 'APC Corp.'
5
+ VENDOR_BROCADE = 'Brocade Communications Corp.'
6
+ VENDOR_CISCO = 'Cisco Systems, Inc.'
7
+ VENDOR_CITRIX = 'Citrix Systems, Inc.'
8
+ VENDOR_DELL = 'Dell Inc.'
9
+ VENDOR_EMULEX = 'Emulex Corp.'
10
+ VENDOR_F5 = 'F5 Networks, Inc.'
11
+ VENDOR_HP = 'Hewlett Packard, Inc.'
12
+ VENDOR_IBM = 'IBM Corp.'
13
+ VENDOR_INTEL = 'Intel Corp.'
14
+ VENDOR_MICROSOFT = 'Microsoft Corp.'
15
+ VENDOR_ORACLE = 'Oracle Corp.'
16
+ VENDOR_QLOGIC = 'QLogic Corp.'
17
+ VENDOR_REDHAT = 'Red Hat Inc.'
18
+ VENDOR_SUSE = 'SUSE Linux GmbH'
19
+ VENDOR_VMWARE = 'VMware, Inc.'
20
+ end
@@ -0,0 +1,8 @@
1
+ class Hash
2
+ def strip_string_values_in_hash
3
+ self.each_pair do |key, val|
4
+ val.strip_string_values_in_array if val.is_a?(Array)
5
+ self[key] = val.strip if val.is_a?(String)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,51 @@
1
+ module Boris; module Profiles
2
+ module Structure
3
+ def scrub_data!
4
+ [ @file_systems,
5
+ @hosted_shares,
6
+ @installed_applications,
7
+ @installed_patches,
8
+ @installed_services,
9
+ @local_user_groups,
10
+ @network_interfaces
11
+ ].each {|arr| arr.strip_string_values_in_array}
12
+ debug 'string values from within data arrays cleaned up'
13
+
14
+ [@hardware, @network_id, @operating_system].each {|h| h.strip_string_values_in_hash}
15
+ debug 'string values from within data hashes cleaned up'
16
+
17
+ @installed_applications.each do |app|
18
+ app[:license_key].upcase! unless !app[:license_key]
19
+ app[:name].string_clean
20
+ app[:vendor].format_vendor unless !app[:vendor]
21
+ end
22
+ debug 'installed application data cleaned up'
23
+
24
+ @network_id[:hostname].upcase!
25
+ @network_id[:domain].downcase! unless !@network_id[:domain]
26
+ debug 'network id data cleaned up'
27
+
28
+ @network_interfaces.each do |interface|
29
+ interface[:fabric_name].downcase! unless !interface[:fabric_name]
30
+ interface[:mac_address].upcase! unless !interface[:mac_address]
31
+ interface[:model] = interface[:model].format_model unless !interface[:model]
32
+ interface[:node_wwn].downcase! unless !interface[:node_wwn]
33
+ interface[:port_wwn].downcase! unless !interface[:port_wwn]
34
+ interface[:remote_mac_address].upcase! unless !interface[:remote_mac_address]
35
+ interface[:vendor] = interface[:vendor].format_vendor unless !interface[:vendor]
36
+ end
37
+ debug 'network interface data cleaned up'
38
+
39
+ @hardware[:cpu_vendor] = @hardware[:cpu_vendor].string_clean.format_vendor unless !@hardware[:cpu_vendor]
40
+ @hardware[:model] = @hardware[:model].format_model unless !@hardware[:model]
41
+ @hardware[:serial].upcase! unless !@hardware[:serial]
42
+ @hardware[:vendor] = @hardware[:vendor].string_clean.format_vendor unless !@hardware[:vendor]
43
+ debug 'network interface data cleaned up'
44
+
45
+ @operating_system[:license_key].upcase! unless !@operating_system[:license_key]
46
+ debug 'operating system data cleaned up'
47
+
48
+ debug 'data scrubbing complete'
49
+ end
50
+ end
51
+ end; end
@@ -0,0 +1,130 @@
1
+ class String
2
+ include Boris
3
+
4
+ def after_colon
5
+ generic_after(':')
6
+ end
7
+
8
+ def after_period
9
+ generic_after('\.')
10
+ end
11
+
12
+ def after_pipe
13
+ generic_after('|')
14
+ end
15
+
16
+ def after_slash
17
+ generic_after('\\\\|\/')
18
+ end
19
+
20
+ def before_colon
21
+ generic_before(':')
22
+ end
23
+
24
+ def before_period
25
+ generic_before('\.')
26
+ end
27
+
28
+ def before_pipe
29
+ generic_before('|')
30
+ end
31
+
32
+ def before_slash
33
+ generic_before('\\\\|\/')
34
+ end
35
+
36
+ def between_parenthesis
37
+ x = self.scan(/\((.*)\)/)
38
+ return x.empty? ? nil : x.join
39
+ end
40
+
41
+ def format_model
42
+ return nil if self == ''
43
+
44
+ # delete models containing "server" or beginning with "ibm"
45
+ # also remove configuration numbers appended (typically on IBM
46
+ # products... ex 'System x1000 M3 -[123456]-')
47
+ model = self.gsub(/(^ibm|server)/i, '').split(/-*(\[|\()/)[0]
48
+
49
+ model = if model =~ /^sun.*blade/i
50
+ 'SunBlade ' + model.scan(/\d/).join
51
+ elsif model =~ /^sun.*fire/i
52
+ 'SunFire ' + model.scan(/\d/).join
53
+ elsif model =~ /^T\d{4}/
54
+ 'SPARC Enterprise ' + model
55
+ elsif model =~ /^big-*ip/i
56
+ model.sub(/^big-*ip/i, 'BIG-IP')
57
+ elsif model =~ /^wsc\d{4}-*.*/i
58
+ 'Catalyst ' + (model.scan(/\d/).join + '-' + model.scan(/[a-z]$/i).join).sub(/-$/, '')
59
+ else
60
+ model
61
+ end
62
+
63
+ model.strip
64
+ end
65
+
66
+ def format_serial
67
+ return nil if self =~ /(^$|\(*none\)*)/i
68
+
69
+ self.upcase
70
+ end
71
+
72
+ def string_clean
73
+ # remove registered "(R)" mark
74
+ string = self.gsub(/\(r\)/i, '')
75
+
76
+ string.encode(Encoding.find('ASCII'), :undef=>:replace, :replace=>'').strip
77
+ end
78
+
79
+ def format_vendor
80
+ return nil if self == ''
81
+
82
+ vendor = self
83
+
84
+ vendor = if vendor =~ /^(amd|authenticamd)/i; VENDOR_AMD
85
+ elsif vendor =~ /^brocade/i; VENDOR_BROCADE
86
+ elsif vendor =~ /^citrix/i; VENDOR_CITRIX
87
+ elsif vendor =~ /^dell/i; VENDOR_DELL
88
+ elsif vendor =~ /^emulex/i; VENDOR_EMULEX
89
+ elsif vendor =~ /^(compaq|hp|hewlett packard)/i; VENDOR_HP
90
+ elsif vendor =~ /^ibm/i; VENDOR_IBM
91
+ elsif vendor =~ /^(genuineintel|intel )/i; VENDOR_INTEL
92
+ elsif vendor =~ /^(microsoft)/i; VENDOR_MICROSOFT
93
+ elsif vendor =~ /^(oracle|sun[w]*|sun microsys)/i; VENDOR_ORACLE
94
+ elsif vendor =~ /^qlogic/i; VENDOR_QLOGIC
95
+ elsif vendor =~ /^red\s*hat/i; VENDOR_REDHAT
96
+ elsif vendor =~ /^suse linux/i; VENDOR_SUSE
97
+ elsif vendor =~ /^vmware/i; VENDOR_VMWARE
98
+ else vendor
99
+ end
100
+
101
+ vendor.strip
102
+ end
103
+
104
+ def generic_after(delimiter)
105
+ x = self.scan(/^.*[#{delimiter}](.*)$/)
106
+ return x.empty? ? nil : x.join.strip
107
+ end
108
+
109
+ def generic_before(delimiter)
110
+ x = self.scan(/^(.*?)[#{delimiter}]/)
111
+ return x.empty? ? nil : x.join.strip
112
+ end
113
+
114
+ def hex_to_address
115
+ self.scan(/../).map {|octet| octet.hex}.join('.')
116
+ end
117
+
118
+ def remove_arch
119
+ String.new(self).remove_arch!
120
+ end
121
+
122
+ def remove_arch!
123
+ self.replace(self.gsub(/\s+\(*(32|64)(-|\s)*bit\)*/, ''))
124
+ end
125
+
126
+ def within_quotes
127
+ x = self.scan(/["|'](.*?)["|']/).flatten
128
+ return x.empty? ? nil : x
129
+ end
130
+ end
@@ -0,0 +1,47 @@
1
+ class BorisLogger < Logger
2
+ def initialize(output)
3
+ super(output)
4
+
5
+ self.datetime_format = '%m-%d-%Y %H:%M:%S'
6
+
7
+ self.formatter = proc do |severity, time, progname, msg|
8
+ sprintf("%-6s %-20s %-20s %-s\n", severity, time, progname, msg)
9
+ end
10
+ end
11
+ end
12
+
13
+ module Boris
14
+ module Lumberjack
15
+ attr_accessor :logger
16
+
17
+ def debug(msg)
18
+ logger.add(Logger::DEBUG, append_target_name(msg), facility) if logger && logger.debug?
19
+ end
20
+
21
+ def info(msg)
22
+ logger.add(Logger::INFO, append_target_name(msg), facility) if logger && logger.info?
23
+ end
24
+
25
+ def warn(msg)
26
+ logger.add(Logger::WARN, append_target_name(msg), facility) if logger && logger.warn?
27
+ end
28
+
29
+ def error(msg)
30
+ logger.add(Logger::ERROR, append_target_name(msg), facility) if logger && logger.error?
31
+ end
32
+
33
+ def fatal(msg)
34
+ logger.add(Logger::FATAL, append_target_name(msg), facility) if logger && logger.fatal?
35
+ end
36
+
37
+ private
38
+
39
+ def append_target_name(msg)
40
+ @host ? "#{@host}: #{msg}" : msg
41
+ end
42
+
43
+ def facility
44
+ @facility ||= self.class.name.gsub(/::/, '.').gsub(/([a-z])([A-Z])/, "\\1_\\2").downcase
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,86 @@
1
+ module Boris
2
+ class Options
3
+ attr_accessor :options
4
+
5
+ # Creates our options hash where the user can pass in an optional hash to immediately
6
+ # override the default values.
7
+ #
8
+ # credentials = [{:user=>'joe', :password=>'mypassword', :connection_types=>[:ssh, :wmi]}]
9
+ # ssh_keys = ['/home/joe/private_key']
10
+ # options = Boris::Options.new(:log_level=>:debug, :ssh_options=>{:keys=>ssh_keys}, :credentials=>credentials)
11
+ #
12
+ # @option options [Boolean] :auto_scrub_data should the target's data be scrubbed
13
+ # after running #retrieve_all?
14
+ # @option options [Array] :credentials an array of credentials in the format of
15
+ # +:user+, +:password+, +:connection_types+. Only +:user+ is mandatory.
16
+ # @option options [Symbol] :log_level The level of logging. Options are:
17
+ # +:debug+, +:info+, +:warn+, +:error+, +:fatal (default)+
18
+ # @option options [Array] profiles An array of module names of the profiles we wish
19
+ # to have available for use on this target. {Boris::Profiles::RedHat} and
20
+ # {Profiles::Solaris} are always the defaults, and Windows profiles are included
21
+ # as defaults as well if {Boris} is running on a Windows host (where WMI connections
22
+ # are available)
23
+ # @option options [Hash] snmp_options A hash of options supported by ruby-snmp.
24
+ # @option options [Hash] ssh_options A hash of options supported by net-ssh.
25
+ #
26
+ # @raise ArgumentError when invalid arguments are passed
27
+ def initialize(options={})
28
+ @options = {}
29
+
30
+ # set our defaults
31
+ @options[:auto_scrub_data] ||= true
32
+ @options[:credentials] ||= []
33
+ @options[:log_level] ||= :fatal
34
+ @options[:profiles] ||= [Profiles::RedHat, Profiles::Solaris]
35
+ @options[:profiles].concat([Profiles::Windows::Windows2003, Profiles::Windows::Windows2008, Profiles::Windows::Windows2012]) if PLATFORM == :win32
36
+ @options[:snmp_options] ||= {}
37
+ @options[:ssh_options] ||= {}
38
+
39
+ invalid_options = options.keys - @options.keys
40
+ if invalid_options.any?
41
+ raise ArgumentError, "invalid options specified (#{invalid_options.join(", ")})"
42
+ end
43
+
44
+ # override the defaults with passed in Options
45
+ @options.merge!(options)
46
+ end
47
+
48
+ # Getter method for grabbing a value from the Options.
49
+ # puts options[:log_level] #=> :debug
50
+ #
51
+ # @param key symbol of the key-value pair
52
+ # @return returns the value of specified key from Options
53
+ def [](key)
54
+ @options[key]
55
+ end
56
+
57
+ # Setter method for setting the value in the options hash
58
+ # puts options[:log_level] #=> :debug
59
+ # options[:log_level] = :info
60
+ # puts options[:log_level] #=> :info
61
+ # @raise ArgumentError when invalid options are provided
62
+ def []=(key, val)
63
+ raise ArgumentError, 'invalid option provided' if !@options.has_key?(key)
64
+ @options[key] = val
65
+ end
66
+
67
+ # Provides a simple mechanism for adding credentials to the credentials array of Options.
68
+ #
69
+ # @param cred [Hash] a credential hash. Values include +:user+, +:password+, and
70
+ # +:connection_types+. +:user+ is mandatory, and +:connection_types+ should be an Array.
71
+ # @raise ArgumentError when invalid credentials or connection_types are supplied
72
+ def add_credential(cred)
73
+ raise ArgumentError, 'invalid credential supplied (must be Hash)' if !cred.kind_of?(Hash)
74
+ raise ArgumentError, 'username required' if !cred[:user]
75
+
76
+ cred[:connection_types] ||= VALID_CONNECTION_TYPES
77
+
78
+ invalid_options = cred[:connection_types] - VALID_CONNECTION_TYPES
79
+ if invalid_options.any?
80
+ raise ArgumentError, "invalid connection method specified (#{invalid_options.join(', ')})"
81
+ end
82
+
83
+ @options[:credentials] << cred unless @options[:credentials].include?(cred)
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,77 @@
1
+ require 'boris/profiles/linux_core'
2
+
3
+ module Boris; module Profiles
4
+ module RedHat
5
+ include Linux
6
+
7
+ def self.connection_type
8
+ Linux.connection_type
9
+ end
10
+
11
+ def self.matches_target?(connector)
12
+ release_data = connector.values_at(%q{ls -d /etc/[A-Za-z]*[_-][rv]e[lr]* | grep -v "lsb|system" | cut -d '/' -f3 | cut -d '-' -f1 | cut -d '_' -f1}).join(' ')
13
+ return true if release_data =~ /redhat/i
14
+ end
15
+
16
+ def get_file_systems; super; end
17
+ def get_hardware; super; end
18
+
19
+ def get_hosted_shares
20
+ super
21
+
22
+ # TODO add code for gathering list of hosted shares from redhat
23
+ end
24
+
25
+ def get_installed_applications
26
+ super
27
+
28
+ application_data = @connector.values_at('rpm -qa --queryformat "%{NAME}|%{VERSION}|%{VENDOR}|%{ARCH}|%{INSTALLTIME:date}\n" | sort')
29
+
30
+ application_data.each do |application|
31
+ application = application.split('|')
32
+ h = installed_application_template
33
+
34
+ h[:date_installed] = DateTime.parse(application[4])
35
+ h[:install_location] = nil
36
+ h[:name] = application[0]
37
+ h[:vendor] = application[2]
38
+ h[:version] = application[1]
39
+
40
+ @installed_applications << h
41
+ end
42
+ end
43
+
44
+ def get_installed_patches; super; end
45
+
46
+ def get_installed_services
47
+ super
48
+ service_data = @connector.values_at("/sbin/chkconfig --list | awk {'print $1'}")
49
+
50
+ service_data.each do |service|
51
+ h = installed_service_template
52
+ h[:name] = service
53
+
54
+ @installed_services << h
55
+ end
56
+ end
57
+
58
+ def get_local_user_groups; super; end
59
+ def get_network_id; super; end
60
+ def get_network_interfaces; super; end
61
+
62
+ def get_operating_system
63
+ super
64
+
65
+ os_install_date = @connector.value_at("rpm -qa basesystem --queryformat '%{INSTALLTIME:date}\n'")
66
+ kernel_version = @connector.value_at('uname -r')
67
+ os_data = @connector.values_at('lsb_release -a | egrep -i "description|release"')
68
+
69
+ @operating_system[:date_installed] = DateTime.parse(os_install_date)
70
+ @operating_system[:kernel] = kernel_version
71
+
72
+ os_base_name = os_data.grep(/^description/i)[0].after_colon
73
+ @operating_system[:name] = os_base_name.split(/ linux /i)[0] + ' Linux'
74
+ @operating_system[:version] = os_base_name.scan(/linux (.*) release/i).join + ' ' + os_data.grep(/^release/i)[0].after_colon
75
+ end
76
+ end
77
+ end; end