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,126 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6
+ <title>
7
+ Top Level Namespace
8
+
9
+ &mdash; Documentation by YARD 0.8.3
10
+
11
+ </title>
12
+
13
+ <link rel="stylesheet" href="css/style.css" type="text/css" media="screen" charset="utf-8" />
14
+
15
+ <link rel="stylesheet" href="css/common.css" type="text/css" media="screen" charset="utf-8" />
16
+
17
+ <script type="text/javascript" charset="utf-8">
18
+ hasFrames = window.top.frames.main ? true : false;
19
+ relpath = '';
20
+ framesUrl = "frames.html#!" + escape(window.location.href);
21
+ </script>
22
+
23
+
24
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
25
+
26
+ <script type="text/javascript" charset="utf-8" src="js/app.js"></script>
27
+
28
+
29
+ </head>
30
+ <body>
31
+ <div id="header">
32
+ <div id="menu">
33
+
34
+ <a href="_index.html">Index</a> &raquo;
35
+
36
+
37
+ <span class="title">Top Level Namespace</span>
38
+
39
+
40
+ <div class="noframes"><span class="title">(</span><a href="." target="_top">no frames</a><span class="title">)</span></div>
41
+ </div>
42
+
43
+ <div id="search">
44
+
45
+ <a class="full_list_link" id="class_list_link"
46
+ href="class_list.html">
47
+ Class List
48
+ </a>
49
+
50
+ <a class="full_list_link" id="method_list_link"
51
+ href="method_list.html">
52
+ Method List
53
+ </a>
54
+
55
+ <a class="full_list_link" id="file_list_link"
56
+ href="file_list.html">
57
+ File List
58
+ </a>
59
+
60
+ </div>
61
+ <div class="clear"></div>
62
+ </div>
63
+
64
+ <iframe id="search_frame"></iframe>
65
+
66
+ <div id="content"><h1>Top Level Namespace
67
+
68
+
69
+
70
+ </h1>
71
+
72
+ <dl class="box">
73
+
74
+
75
+
76
+
77
+
78
+
79
+
80
+
81
+ </dl>
82
+ <div class="clear"></div>
83
+
84
+ <h2>Defined Under Namespace</h2>
85
+ <p class="children">
86
+
87
+
88
+ <strong class="modules">Modules:</strong> <span class='object_link'><a href="Boris.html" title="Boris (module)">Boris</a></span>
89
+
90
+
91
+
92
+ <strong class="classes">Classes:</strong> <span class='object_link'><a href="Array.html" title="Array (class)">Array</a></span>, <span class='object_link'><a href="BorisLogger.html" title="BorisLogger (class)">BorisLogger</a></span>, <span class='object_link'><a href="Hash.html" title="Hash (class)">Hash</a></span>, <span class='object_link'><a href="String.html" title="String (class)">String</a></span>
93
+
94
+
95
+ </p>
96
+
97
+ <h2>Constant Summary</h2>
98
+
99
+ <dl class="constants">
100
+
101
+ <dt id="PLATFORM-constant" class="">PLATFORM =
102
+
103
+ </dt>
104
+ <dd><pre class="code"><span class='const'>RbConfig</span><span class='op'>::</span><span class='const'>CONFIG</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>host_os</span><span class='tstring_end'>'</span></span><span class='rbracket'>]</span> <span class='op'>=~</span> <span class='tstring'><span class='regexp_beg'>/</span><span class='tstring_content'>mswin|mingw|cygwin</span><span class='regexp_end'>/</span></span> <span class='op'>?</span> <span class='symbol'>:win32</span> <span class='op'>:</span> <span class='const'>RbConfig</span><span class='op'>::</span><span class='const'>CONFIG</span><span class='lbracket'>[</span><span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>host_os</span><span class='tstring_end'>'</span></span><span class='rbracket'>]</span></pre></dd>
105
+
106
+ </dl>
107
+
108
+
109
+
110
+
111
+
112
+
113
+
114
+
115
+
116
+
117
+ </div>
118
+
119
+ <div id="footer">
120
+ Generated on Sun Feb 3 16:32:41 2013 by
121
+ <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
122
+ 0.8.3 (ruby-1.9.3).
123
+ </div>
124
+
125
+ </body>
126
+ </html>
data/lib/boris.rb ADDED
@@ -0,0 +1,30 @@
1
+ # encoding: UTF-8
2
+
3
+ PLATFORM = RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/ ? :win32 : RbConfig::CONFIG['host_os']
4
+
5
+ require 'date'
6
+ require 'json'
7
+ require 'logger'
8
+ require 'netaddr'
9
+ require 'net/ssh'
10
+ require 'rbconfig'
11
+ require 'snmp'
12
+ require 'socket'
13
+ require 'thread'
14
+ require 'win32ole' if PLATFORM == :win32
15
+
16
+ require 'boris/lumberjack'
17
+
18
+ require 'boris/errors'
19
+ require 'boris/options'
20
+ require 'boris/target'
21
+
22
+ require 'boris/helpers/array'
23
+ require 'boris/helpers/constants'
24
+ require 'boris/helpers/hash'
25
+ require 'boris/helpers/scrubber'
26
+ require 'boris/helpers/string'
27
+
28
+ module Boris
29
+
30
+ end
@@ -0,0 +1,47 @@
1
+ module Boris
2
+ class Connector
3
+ include Lumberjack
4
+
5
+ attr_reader :connected
6
+ attr_reader :host
7
+ attr_reader :options
8
+ attr_reader :reconnectable
9
+
10
+ def initialize(host, cred, options, logger=nil)
11
+ debug 'creating connection object'
12
+
13
+ @host = host
14
+ @user = cred[:user]
15
+ @password = cred[:password]
16
+ @connected = false
17
+ @reconnectable = true
18
+
19
+ @logger = logger
20
+ end
21
+
22
+ def connected?
23
+ @connected
24
+ end
25
+
26
+ def disconnect
27
+ debug 'closing connection to host'
28
+ @connected = false
29
+ end
30
+
31
+ def establish_connection
32
+ debug 'attempting connection'
33
+ end
34
+
35
+ def values_at(request, limit)
36
+ if !limit.kind_of?(Integer)
37
+ raise ArgumentError, "non-integer limit specified (#{limit.inspect})"
38
+ elsif limit < 1
39
+ raise ArgumentError, "specified limit must be greater than 1 (or nil for no limit) (#{limit.inspect})"
40
+ end unless limit.nil?
41
+
42
+ amount = limit == 1 ? 'single value' : 'multiple values'
43
+
44
+ debug "issuing request for #{amount} (#{request.inspect})"
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,56 @@
1
+ require 'boris/connectors'
2
+
3
+ module Boris
4
+ class SNMPConnector < Connector
5
+ def initialize(host, cred, options, logger=nil)
6
+ super(host, cred, options, logger)
7
+ @snmp_options = options[:snmp_options].merge(:host=>@host, :version=>:SNMPv1, :community=>@user)
8
+
9
+ #snmp connections are always reconnectable
10
+ @reconnectable = true
11
+ end
12
+
13
+ def disconnect
14
+ super
15
+ @transport = nil
16
+ debug 'connections closed'
17
+ end
18
+
19
+ def establish_connection
20
+ super
21
+
22
+ begin
23
+ @transport = SNMP::Manager.new(@snmp_options)
24
+ value_at('sysDescr')
25
+ debug 'connection established'
26
+ @connected = true
27
+ rescue SNMP::RequestTimeout
28
+ warn 'connection failed (connection timeout)'
29
+ rescue => error
30
+ warn "connection failed (#{error.message})"
31
+ end
32
+
33
+ return self
34
+ end
35
+
36
+ def value_at(request)
37
+ values_at(request, 1)[0]
38
+ end
39
+
40
+ def values_at(request, limit=nil)
41
+ super(request, limit)
42
+
43
+ return_data = []
44
+
45
+ @transport.walk(request) do |row|
46
+ row.each {|item| return_data << {:name=>item.name.to_s, :value=>item.value}}
47
+ end
48
+
49
+ info "#{return_data.size} row(s) returned"
50
+
51
+ limit = return_data.size if limit.nil?
52
+
53
+ return_data[0..limit]
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,110 @@
1
+ require 'boris/connectors'
2
+
3
+ module Boris
4
+ class SSHConnector < Connector
5
+ def initialize(host, cred, options, logger=nil)
6
+ @ssh_options = options[:ssh_options]
7
+ @ssh_options[:password] = @password if @password
8
+
9
+ invalid_ssh_options = @ssh_options.keys - Net::SSH::VALID_OPTIONS
10
+ raise ArgumentError, "invalid ssh option(s): #{invalid_ssh_options.join(', ')}" if invalid_ssh_options.any?
11
+
12
+ super(host, cred, options, logger)
13
+ end
14
+
15
+ def disconnect
16
+ super
17
+ @transport = nil
18
+ debug 'connections closed'
19
+ end
20
+
21
+ def establish_connection
22
+ super
23
+
24
+ begin
25
+ @transport = Net::SSH.start(@host, @user, @ssh_options)
26
+ debug 'connection established'
27
+ @connected = @reconnectable = true
28
+ rescue Net::SSH::AuthenticationFailed
29
+ warn "connection failed (connection made but credentials not accepted with user #{@user})"
30
+ @reconnectable = true
31
+ rescue Net::SSH::HostKeyMismatch
32
+ warn 'connection failed (host key mismatch)'
33
+ @reconnectable = false
34
+ rescue => error
35
+ warn "connection failed (#{error.message})"
36
+ @reconnectable = true
37
+ end
38
+
39
+ if @reconnectable == true
40
+ info 'connection available for retry'
41
+ elsif @reconnectable == false
42
+ info 'connection does not seem to be available (so we will not retry)'
43
+ end unless @transport
44
+
45
+ return self
46
+ end
47
+
48
+ def value_at(request, request_pty=false)
49
+ values_at(request, request_pty, 1)[0]
50
+ end
51
+
52
+ def values_at(request, request_pty=false, limit=nil)
53
+ super(request, limit)
54
+
55
+ error_messages = []
56
+ reconnect = false
57
+ return_data = []
58
+
59
+ chan = @transport.open_channel do |chan|
60
+ if request_pty
61
+ debug 'requsting pty...'
62
+ chan.request_pty()
63
+ debug 'pty successfully requested'
64
+ end
65
+
66
+ chan.on_data do |ch, data|
67
+ if data =~ /^\[sudo\] password for/i
68
+ debug 'system asking for password for sudo request'
69
+ if @password
70
+ ch.send_data "#{@password}\n"
71
+ debug 'password sent'
72
+ else
73
+ ch.close
74
+ info "channel closed (we don't have a password to supply)"
75
+ end
76
+ elsif data =~ /sorry, try again/i
77
+ ch.close
78
+ return_data = []
79
+ info "channel closed (we have a password to supply but system its not accepted)"
80
+ elsif data =~ /permission denied/i
81
+ warn "permission denied for this request (#{data.gsub(/\n|\s+/, ', ')})"
82
+ else
83
+ return_data << data
84
+ end
85
+ end
86
+
87
+ # called when something is written to stderr
88
+ chan.on_extended_data do |ch, type, data|
89
+ error_messages.concat(data.split(/\n/))
90
+ end
91
+
92
+ chan.exec(request)
93
+ end
94
+
95
+ chan.wait
96
+
97
+ if !error_messages.empty?
98
+ warn "message written to STDERR for this request (#{error_messages.join('. ')})"
99
+ end
100
+
101
+ return_data = return_data.join.split(/\n/)
102
+
103
+ info "#{return_data.size} row(s) returned"
104
+
105
+ limit = return_data.size if limit.nil?
106
+
107
+ return_data[0..limit]
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,186 @@
1
+ require 'boris/connectors'
2
+
3
+ module Boris
4
+ class WMIConnector < Connector
5
+ attr_accessor :wmi, :root_wmi, :registry
6
+
7
+ HKEY_LOCAL_MACHINE = 0x80000002
8
+ KEY_QUERY_VALUE = 1
9
+ KEY_ENUMERATE_SUB_KEYS = 8
10
+
11
+ def initialize(host, cred, options, logger=nil)
12
+ super(host, cred, options, logger)
13
+ end
14
+
15
+ def disconnect
16
+ super
17
+ @wmi = nil
18
+ @registry = nil
19
+ @root_wmi = nil
20
+
21
+ debug 'connections closed'
22
+ end
23
+
24
+ def establish_connection
25
+ super
26
+
27
+ begin
28
+ locator = WIN32OLE.new('WbemScripting.SWbemLocator')
29
+
30
+ debug 'attempting connection to cimv2 namespace'
31
+ @wmi = locator.ConnectServer(@host, 'root\cimv2', @user, @password, nil, nil, 128)
32
+ debug 'connection to cimv2 namespace successful'
33
+
34
+ debug 'attempting connection to wmi root namespace'
35
+ @root_wmi = locator.ConnectServer(@host, 'root\WMI', @user, @password, nil, nil, 128)
36
+ debug 'connection to wmi root namespace successful'
37
+
38
+ debug 'attempting connection to registry'
39
+ @registry = locator.ConnectServer(@host, 'root\default', @user, @password, nil, nil, 128).Get('StdRegProv')
40
+ debug 'connection to registry successful'
41
+
42
+ debug 'all required connections established'
43
+ @connected = @reconnectable = true
44
+
45
+ rescue WIN32OLERuntimeError => error
46
+ @connected = false
47
+ if error.message =~ /access is denied/i
48
+ warn "connection failed (connection made but credentials not accepted with user #{@user})"
49
+ @reconnectable = true
50
+ elsif error.message =~ /rpc server is unavailable/i
51
+ warn 'connection failed (rpc server not available)'
52
+ @reconnectable = false
53
+ else
54
+ warn "connection failed (#{error.message.gsub(/\n\s*/, '. ')})"
55
+ @reconnectable = true
56
+ end
57
+ end
58
+
59
+ if @reconnectable == true
60
+ info 'connection available for retry'
61
+ elsif @reconnectable == false
62
+ info 'connection does not seem to be available (so we will not retry)'
63
+ end unless @transport
64
+
65
+ return self
66
+ end
67
+
68
+ def value_at(request, conn=:wmi)
69
+ values_at(request, conn, limit=1)[0]
70
+ end
71
+
72
+ def values_at(request, conn=:wmi, limit=nil)
73
+ super(request, limit)
74
+
75
+ rows = case conn
76
+ when :root_wmi
77
+ @root_wmi.ExecQuery(request, nil, 48)
78
+ when :wmi
79
+ @wmi.ExecQuery(request, nil, 48)
80
+ end
81
+
82
+ return_data = []
83
+
84
+ i = 0
85
+
86
+ rows.each do |row|
87
+ i += 1
88
+
89
+ return_hash = {}
90
+
91
+ row.Properties_.each do |property|
92
+ if property.Name =~ /^attributes/i && property.Value.kind_of?(WIN32OLE)
93
+ row.Attributes.Properties_.each do |property|
94
+ return_hash[property.Name.downcase.to_sym] = property.Value
95
+ end
96
+ else
97
+ return_hash[property.Name.downcase.to_sym] = property.Value
98
+ end
99
+ end
100
+
101
+ return_data << return_hash
102
+
103
+ break if (limit.nil? && i == limit)
104
+ end
105
+
106
+ info "#{return_data.size} row(s) returned"
107
+
108
+ return return_data
109
+ end
110
+
111
+ def has_access_for(key_path, permission_to_check=nil)
112
+ debug "checking for registry read access for #{key_path}"
113
+
114
+ access_params = @registry.Methods_('CheckAccess').inParameters.SpawnInstance_
115
+
116
+ access_params.hDefKey = HKEY_LOCAL_MACHINE
117
+ access_params.sSubKeyName = key_path
118
+ access_params.uRequired = permission_to_check
119
+
120
+ @registry.ExecMethod_('CheckAccess', access_params).bGranted
121
+ end
122
+
123
+ def registry_subkeys_at(key_path)
124
+ return_data = []
125
+
126
+ debug "reading registry subkeys at path #{key_path}"
127
+
128
+ if has_access_for(key_path, KEY_ENUMERATE_SUB_KEYS)
129
+ in_params = @registry.Methods_('EnumKey').inParameters.SpawnInstance_
130
+ in_params.hDefKey = HKEY_LOCAL_MACHINE
131
+ in_params.sSubKeyName = key_path
132
+
133
+ @registry.ExecMethod_('EnumKey', in_params).sNames.each do |key|
134
+ return_data << key_path + '\\' + key
135
+ end
136
+ else
137
+ info "no access for enumerating keys at (#{key_path})"
138
+ end
139
+
140
+ return return_data
141
+ end
142
+
143
+ def registry_values_at(key_path)
144
+ values = Hash.new
145
+
146
+ debug "reading registry values at path #{key_path}"
147
+
148
+ if has_access_for(key_path, KEY_QUERY_VALUE)
149
+ in_params = @registry.Methods_('EnumValues').inParameters.SpawnInstance_
150
+ in_params.hDefKey = HKEY_LOCAL_MACHINE
151
+ in_params.sSubKeyName = key_path
152
+
153
+ str_params = @registry.Methods_('GetStringValue').inParameters.SpawnInstance_
154
+ str_params.sSubKeyName = key_path
155
+
156
+ subkey_values = @registry.ExecMethod_('EnumValues', in_params).sNames
157
+ subkey_values ||= []
158
+
159
+ subkey_values.each do |value|
160
+ if !value.empty?
161
+ str_params.sValueName = value
162
+
163
+ begin
164
+ x = @registry.ExecMethod_('GetStringValue', str_params).sValue
165
+ x = @registry.ExecMethod_('GetBinaryValue', str_params).uValue unless x
166
+ x = @registry.ExecMethod_('GetDWORDValue', str_params).uValue unless x
167
+ x = @registry.ExecMethod_('GetExpandedStringValue', str_params).sValue unless x
168
+ x = @registry.ExecMethod_('GetMultiStringValue', str_params).sValue unless x
169
+ x = @registry.ExecMethod_('GetQWORDValue', str_params).uValue unless x
170
+
171
+ values[value.downcase.to_sym] = x
172
+ rescue
173
+ if $!.message =~ /#{invalid method}/i
174
+ warn "unreadable registry value (#{key_path}\\#{value})"
175
+ end
176
+ end
177
+ end
178
+ end
179
+ else
180
+ info "no access for enumerating values at (#{key_path})"
181
+ end
182
+
183
+ return values
184
+ end
185
+ end
186
+ end