marty 1.1.5 → 1.1.6

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.
@@ -0,0 +1,28 @@
1
+ class Diagnostic::Request
2
+ def self.request
3
+ raise 'Request object has not been been injected into #{name}' unless
4
+ @@request
5
+
6
+ @@request
7
+ end
8
+
9
+ def self.request= req
10
+ @@request = req
11
+ end
12
+
13
+ def self.params
14
+ request.params
15
+ end
16
+
17
+ def self.scope
18
+ params[:scope]
19
+ end
20
+
21
+ def self.op
22
+ params[:op]
23
+ end
24
+
25
+ def self.ssl?
26
+ request.port == 443
27
+ end
28
+ end
@@ -0,0 +1,17 @@
1
+ class Diagnostic::Version < Diagnostic::Base
2
+ def self.generate
3
+ pack do
4
+ begin
5
+ message = `cd #{Rails.root.to_s}; git describe --tags --always;`.strip
6
+ rescue
7
+ message = error("Failed accessing git")
8
+ end
9
+ {
10
+ 'Marty' => Marty::VERSION,
11
+ 'Delorean' => Delorean::VERSION,
12
+ 'Mcfly' => Mcfly::VERSION,
13
+ 'Git' => message,
14
+ }
15
+ end
16
+ end
17
+ end
@@ -6,14 +6,6 @@ class Marty::Helper
6
6
  Kernel.sleep seconds
7
7
  end
8
8
 
9
- delorean_fn :my_ip, sig:0 do
10
- Socket.ip_address_list.detect{|intf| intf.ipv4_private?}.ip_address
11
- end
12
-
13
- delorean_fn :git, sig:0 do
14
- [my_ip, ENV['DELAYED_VER']]
15
- end
16
-
17
9
  delorean_fn :range_step, sig: 3 do
18
10
  |rstart, rend, step|
19
11
  (rstart..rend).step(step).to_a
@@ -1,34 +1,30 @@
1
- <% inconsistent = diff(data) %>
2
1
  <h3><%=name.demodulize%></h3>
3
- <%='<h3 class="error">Issues Detected</h3>' if
4
- inconsistent%>
2
+ <%='<h3 class="error">Inconsistency Detected</h3>' unless consistent %>
5
3
  <div class="wrapper">
6
4
  <table>
7
- <%# Create node table headers if applicable %>
5
+ <%# create node table headers if applicable %>
8
6
  <tr>
9
- <%='<th></th>' if inconsistent %>
7
+ <%='<th></th>' unless success %>
10
8
  <% data.keys.each do |node| %>
11
- <th <%='colspan="2"' unless inconsistent %> scope="col">
12
- <%= inconsistent ? node :
13
- (type == 'local' ? 'local' : 'consistent') %>
9
+ <th <%='colspan="2"' if success %> scope="col">
10
+ <%= success ? 'consistent' : node %>
14
11
  </th>
15
- <% break unless inconsistent %>
12
+ <% break if success %>
16
13
  <% end %>
17
14
  </tr>
18
- <%# Create row headers and display node results %>
19
- <% data[data.keys.first].each do |key, value| %>
15
+ <%# create row headers and display node results %>
16
+ <% data.values.map{|v| v.keys}.flatten.compact.uniq.each do |test| %>
20
17
  <tr>
21
- <th scope="row"><%= key %></th>
22
- <% targets = get_targets(data) %>
23
- <% data.each do |_node, result| %>
24
- <td class="overflow <%= (is_failure?(value) ||
25
- (result[key].to_s != targets[key].to_s)) ? 'error' :
26
- 'passed' %>">
27
- <%= simple_format(result[key].to_s) %>
18
+ <th class="data" scope="row"><%= test %></th>
19
+ <% data.values.each do |diagnostic| %>
20
+ <td class="overflow <%= display_info_css(diagnostic[test]) %>">
21
+ <%= display_info_description(diagnostic[test]) %>
28
22
  </td>
29
- <% break unless inconsistent %>
23
+ <% break if success %>
30
24
  <% end %>
31
25
  </tr>
32
26
  <% end %>
33
27
  </table>
34
28
  </div>
29
+
30
+ <%= display_alert_message if fatal? %>
@@ -10,13 +10,12 @@
10
10
  color: #333333;
11
11
  font-family: Arial, Helvetica, Verdana, sans-serif;
12
12
  font-weight: normal;
13
- font-size: 9pt; }
13
+ font-size: 9pt;}
14
14
  table { border: none;
15
15
  border-collapse: collapse;
16
16
  display: inline-block;
17
17
  margin: 0px 5px 0px 5px;
18
- text-align: left;
19
- }
18
+ text-align: left;}
20
19
  th { padding: 9px;
21
20
  border: none;
22
21
  background-color: #d6d6d6 }
@@ -24,26 +23,26 @@
24
23
  padding: 9px;
25
24
  }
26
25
  tr { text-align: center;}
27
- tr.passed { background-color: #d0e9c6 }
26
+ td.desc { font-size: 10pt;}
28
27
  td.passed { background-color: #d0e9c6 }
28
+ td.inconsistent { background-color: #ffa500 }
29
29
  td.error { background-color: #ff5555;
30
- color: #ffffff;}
31
- th.error { background-color: #ff5555;}
32
- td.desc { font-size: 10pt; }
30
+ color: #ffffff;}
31
+ td.overflow { max-width: 350px;
32
+ overflow: auto;}
33
+ th.data { text-align: left;}
33
34
  p { white-space: pre-line;}
34
- h1 { display: block;
35
- margin: 0px auto 40px auto;
36
- padding: 8px;
37
- background-color: #1aaa55;
38
- font-size: 18pt;
39
- color: #ffffff;
40
- line-height: 1.5em; }
35
+ h1.application { display: block;
36
+ margin: 0px auto 40px auto;
37
+ padding: 8px;
38
+ background-color: #1aaa55;
39
+ font-size: 18pt;
40
+ color: #ffffff;
41
+ line-height: 1.5em;}
41
42
  h1.error {background-color: #ff5555;}
42
43
  h2 {text-align: center;}
43
44
  h3.error {color: red;}
44
45
  h3 {text-align: center;}
45
- td.overflow { max-width: 350px;
46
- overflow: auto; }
47
46
  .wrapper {
48
47
  overflow-x: auto;
49
48
  white-space: nowrap;
@@ -52,11 +51,11 @@
52
51
  </head>
53
52
  <body>
54
53
  <div style="text-align:center">
55
- <h1 class="<%= 'error' if @result.to_s.include?('error') %>">
56
- <%=Rails.application.class.parent_name%> Diagnostic
54
+ <h1 class="application <%= 'error' unless @result['errors'].empty? %>">
55
+ <%=ENV['DIAG_TITLE'] || Rails.application.class.parent_name%> Diagnostic
57
56
  </h1>
58
57
  <h3><i><%= DateTime.now %></i></h3>
59
- <%== @result %>
58
+ <%== @result['display'] %>
60
59
  </div>
61
60
  </body>
62
61
  </html>
@@ -3,7 +3,7 @@ Delay:
3
3
  # the delay parameter delays the next created job so that a different
4
4
  # worker is more likely to claim it
5
5
  delay =? 2.6
6
- ver = Marty::Helper.sleep(delay) && Marty::Helper.git
6
+ ver = Marty::Helper.sleep(delay) && Diagnostic::Helper.git
7
7
  res = [(Delay() | "ver") for i in Marty::Helper.range_step(0, count, 1)]
8
8
  result = [r.to_a for r in res]
9
9
 
@@ -0,0 +1,28 @@
1
+ module Diagnostic::Database
2
+ def self.db_name
3
+ ActiveRecord::Base.connection_config[:database]
4
+ end
5
+
6
+ def self.db_server_name
7
+ ActiveRecord::Base.connection_config[:host] || 'undefined'
8
+ end
9
+
10
+ def self.db_adapter_name
11
+ ActiveRecord::Base.connection.adapter_name
12
+ end
13
+
14
+ def self.db_time
15
+ ActiveRecord::Base.connection.execute('SELECT NOW();')[0]['now']
16
+ end
17
+
18
+ def self.db_version
19
+ ActiveRecord::Base.connection.execute('SELECT VERSION();')[0]['version']
20
+ end
21
+
22
+ def self.db_schema
23
+ current = ActiveRecord::Migrator.current_version
24
+ raise "Migration is needed.\nCurrent Version: #{current}" if
25
+ ActiveRecord::Migrator.needs_migration?
26
+ current
27
+ end
28
+ end
@@ -0,0 +1,35 @@
1
+ module Diagnostic::Node
2
+ def self.my_ip
3
+ begin
4
+ Socket.ip_address_list.detect{|intf| intf.ipv4_private?}.ip_address
5
+ rescue => e
6
+ e.message
7
+ end
8
+ end
9
+
10
+ def self.get_postgres_connections
11
+ conn = ActiveRecord::Base.connection.execute('SELECT datname,'\
12
+ 'application_name,'\
13
+ 'state,'\
14
+ 'pid,'\
15
+ 'client_addr '\
16
+ 'FROM pg_stat_activity')
17
+ conn.each_with_object({}) do |conn, h|
18
+ h[conn['datname']] ||= []
19
+ h[conn['datname']] << conn.except('datname')
20
+ end
21
+ end
22
+
23
+ def self.get_target_connections target
24
+ get_postgres_connections[Diagnostic::Database.db_name].select{|conn|
25
+ conn['application_name'].include?(target)
26
+ }.map{|conn|
27
+ conn['client_addr'] == '127.0.0.1' ? my_ip : conn['client_addr']
28
+ }.uniq.compact
29
+ end
30
+
31
+ def self.get_nodes
32
+ nodes = get_target_connections('Passenger')
33
+ nodes.empty? ? [my_ip] : nodes
34
+ end
35
+ end
@@ -0,0 +1,47 @@
1
+ module Diagnostic::Packer
2
+ # expects a block that returns either a String or a Hash value and formats
3
+ # it into a diagnostic info object.
4
+ def pack include_ip=true
5
+ begin
6
+ data = yield
7
+ info = case data
8
+ when Hash
9
+ is_valid_info?(data) ? {name.demodulize => data} :
10
+ data.each_with_object({}) do
11
+ |(key, value), hash|
12
+ case value
13
+ when String
14
+ hash[key] = create_info(value)
15
+ when Hash
16
+ raise "Invalid Diagnostic Info #{value}" unless
17
+ is_valid_info?(value)
18
+
19
+ hash[key] = value
20
+ end
21
+ end
22
+ when String
23
+ {name.demodulize => create_info(data)}
24
+ else
25
+ raise "Invalid Data Type: (#{data}, #{data.class}) "\
26
+ "`package` expects a String or Hash value."
27
+ end
28
+ include_ip ? {Diagnostic::Node.my_ip => info} : info
29
+ end
30
+ end
31
+
32
+ def create_info description, status=true, consistent=nil
33
+ {
34
+ 'description' => description,
35
+ 'status' => status,
36
+ 'consistent' => consistent
37
+ }
38
+ end
39
+
40
+ def is_valid_info? info
41
+ info.keys.to_set == Set['description', 'status', 'consistent']
42
+ end
43
+
44
+ def error description
45
+ create_info(description, false)
46
+ end
47
+ end
@@ -1,3 +1,3 @@
1
1
  module Marty
2
- VERSION = "1.1.5"
2
+ VERSION = "1.1.6"
3
3
  end
@@ -4,190 +4,33 @@ module Marty
4
4
  before(:each) { @routes = Marty::Engine.routes }
5
5
  let(:json_response) { JSON.parse(response.body) }
6
6
 
7
- def git
8
- begin
9
- message = `cd #{Rails.root.to_s}; git describe --tags --always;`.strip
10
- rescue
11
- message = error("Failed accessing git")
12
- end
13
- end
14
-
15
- def version
16
- {
17
- "Marty" => Marty::VERSION,
18
- "Delorean" => Delorean::VERSION,
19
- "Mcfly" => Mcfly::VERSION,
20
- "Git" => git,
21
- }
22
- end
23
-
24
- def environment
25
- rbv = "#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL} (#{RUBY_PLATFORM})"
26
- {'Environment' => Rails.env,
27
- 'Rails' => Rails.version,
28
- 'Netzke Core' => Netzke::Core::VERSION,
29
- 'Netzke Basepack' => Netzke::Basepack::VERSION,
30
- 'Ruby' => rbv,
31
- 'RubyGems' => Gem::VERSION,
32
- 'Database Adapter' => described_class::Database.db_adapter_name,
33
- 'Database Server' => described_class::Database.db_server_name,
34
- 'Database Version' => described_class::Database.db_version,
35
- 'Database Schema Version' => described_class::Database.db_schema}
36
- end
37
-
38
- def version_display
39
- <<-ERB
40
- <h3>Version</h3>
41
- <div class="wrapper">
42
- <table>
43
- <tr>
44
- <th colspan="2" scope="col">consistent</th>
45
- </tr>
46
- <tr>
47
- <th scope="row">Marty</th>
48
- <td class="overflow passed"><p>#{Marty::VERSION}</p>
49
- </td>
50
- </tr>
51
- <tr>
52
- <th scope="row">Delorean</th>
53
- <td class="overflow passed"><p>#{Delorean::VERSION}</p>
54
- </td>
55
- </tr>
56
- <tr>
57
- <th scope="row">Mcfly</th>
58
- <td class="overflow passed"><p>#{Mcfly::VERSION}</p>
59
- </td>
60
- </tr>
61
- <tr>
62
- <th scope="row">Git</th>
63
- <td class="overflow passed"><p>#{git}</p>
64
- </td>
65
- </tr>
66
- </table>
67
- </div>
68
- ERB
69
- end
70
-
71
- def version_display_fail val
72
- <<-ERB
73
- <h3>Version</h3>
74
- <h3 class="error">Issues Detected </h3>
75
- <div class="wrapper">
76
- <table>
77
- <tr>
78
- <th></th>
79
- <th scope="col">node1</th>
80
- <th scope="col">node2</th>
81
- </tr>
82
- <tr>
83
- <th scope="row">Marty</th>
84
- <td class="overflow passed"><p>#{Marty::VERSION}</p></td>
85
- <td class="overflow error"><p>#{val}</p></td>
86
- </tr>
87
- <tr>
88
- <th scope="row">Delorean</th>
89
- <td class="overflow passed"><p>#{Delorean::VERSION}</p></td>
90
- <td class="overflow passed"><p>#{Delorean::VERSION}</p></td>
91
- </tr>
92
- <tr>
93
- <th scope="row">Mcfly</th>
94
- <td class="overflow passed"><p>#{Mcfly::VERSION}</p></td>
95
- <td class="overflow passed"><p>#{Mcfly::VERSION}</p></td>
96
- </tr>
97
- <tr>
98
- <th scope="row">Git</th>
99
- <td class="overflow passed"><p>#{git}</p></td>
100
- <td class="overflow passed"><p>#{git}</p></td>
101
- </tr>
102
- </table>
103
- </div>
104
- ERB
105
- end
106
-
107
- def minimize(str)
108
- str.gsub(/\s+/, "")
109
- end
110
-
111
7
  describe 'GET #op' do
112
- it 'returns http success with local scope' do
113
- get :op, op: 'version', scope: 'local'
8
+ it 'returns http success' do
9
+ get :op, format: :json, op: 'version'
114
10
  expect(response).to have_http_status(:success)
115
11
  end
116
12
 
117
- it 'returns the current version JSON' do
118
- get :op, format: :json, op: 'version', scope: 'local'
119
- expect(assigns('result')).to eq(version)
13
+ it 'a request injects the request object into Diagnostic classes' do
14
+ get :op, format: :json, op: 'version'
15
+ expect(Diagnostic::Reporter.request).not_to eq(nil)
120
16
  end
121
17
 
122
- it 'returns the correct environment JSON' do
123
- get :op, format: :json, op: 'environment', scope: 'local'
124
- expect(assigns('result')).to eq(environment)
125
- end
126
-
127
- it 'produces an html display of the diagnostic (version)' do
128
- test = described_class::Version.display({'stub' => version})
129
- expect(minimize(test)).to eq(minimize(version_display))
130
- end
131
-
132
- it 'masks consistent nodes for display (version)' do
133
- data = {'node1' => version, 'node2' => version}
134
- test = described_class::Version.display(data)
135
- expect(minimize(test)).to eq(minimize(version_display))
136
- end
137
-
138
- it 'displays all nodes when there is an inconsistent node (version)' do
139
- ver = '0.0.0'
140
- data = {'node1' => version, 'node2' => version + {'Marty' => ver}}
141
- expected = version_display_fail(ver)
142
- test = described_class::Version.display(data)
143
- expect(minimize(test)).to eq(minimize(expected))
144
- end
145
- end
146
-
147
- describe 'diagnostic classes and aggregate functions' do
148
- it 'has access to DiagnosticController request' do
149
- get :op, op: 'version', scope: 'local'
150
- expect(described_class::Base.request).not_to eq(nil)
151
- end
152
-
153
- it 'can aggregate diagnostics and return appropriate JSON' do
154
- # simulate open-uri nodal diag request
155
- uri_stub = {:open => nil, :readlines => [version.to_json]}
156
- nodes = ['node1', 'node2', 'node3']
157
- expected = nodes.each_with_object({}){|n, h| h[n] = version}
158
-
159
- # mock nodes and diag request to node
160
- allow(described_class::Base.request).to receive(:port).and_return(3000)
161
- allow(described_class::Base).to receive(:get_nodes).and_return(nodes)
162
- allow(described_class::Base).to receive_message_chain(uri_stub)
18
+ it 'returns the current version JSON' do
19
+ get :op, format: :json, op: 'version', data: 'true'
163
20
 
164
- # perform aggregation using Base class function and Version class
165
- expect(described_class::Base.get_nodal_diags('version')).to eq(expected)
166
- expect(described_class::Version.aggregate).to eq(expected)
167
- end
21
+ # generate version data and declare all values consistent
22
+ versions = Diagnostic::Version.generate.each_with_object({}){
23
+ |(n, v),h|
24
+ h[n] = v.each{|t, r| r['consistent'] = true}
25
+ }
168
26
 
169
- # returns true if there are differences in nodes for Base/Version
170
- it 'determines diff of aggregate diagnostic' do
171
- inconsistent = {'1' => version, '2' => version + {'Git' => '123'}}
172
- consistent = inconsistent + {'2' => version}
173
- aggregate_failures do
174
- expect(described_class::Base.diff(inconsistent)).to eq(true)
175
- expect(described_class::Base.diff(consistent)).to eq(false)
176
- expect(described_class::Version.diff(inconsistent)).to eq(true)
177
- expect(described_class::Version.diff(consistent)).to eq(false)
178
- end
179
- end
27
+ expected = {
28
+ 'data' => {
29
+ 'Diagnostic::Version' => versions
30
+ }
31
+ }
180
32
 
181
- it 'can detects errors in diagnostic' do
182
- error_free = version
183
- error_test = version + {'Git' => described_class::Base.
184
- error('Failed accessing git')}
185
- aggregate_failures do
186
- expect(described_class::Base.errors(error_free)).to eq(0)
187
- expect(described_class::Base.errors(error_test)).to eq(1)
188
- expect(described_class::Version.errors(error_free)).to eq(0)
189
- expect(described_class::Version.errors(error_test)).to eq(1)
190
- end
33
+ expect(assigns('result')).to eq(expected)
191
34
  end
192
35
  end
193
36
  end