cloud-toaster 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.
Files changed (69) hide show
  1. checksums.yaml +8 -8
  2. data/Gemfile +5 -45
  3. data/README.md +2 -2
  4. data/VERSION +1 -1
  5. data/chef/cookbooks/lxc/recipes/setup_database.rb +12 -4
  6. data/chef/cookbooks/toaster/recipes/testing.rb +2 -2
  7. data/cloud-toaster.gemspec +94 -0
  8. data/config.json +3 -1
  9. data/lib/toaster/api.rb +25 -22
  10. data/lib/toaster/chef/chef_listener.rb +3 -3
  11. data/lib/toaster/chef/chef_node_inspector.rb +6 -4
  12. data/lib/toaster/chef/chef_util.rb +26 -8
  13. data/lib/toaster/chef/failsafe_resource_parser.rb +1 -0
  14. data/lib/toaster/chef/resource_inspector.rb +1 -1
  15. data/lib/toaster/model/automation.rb +26 -7
  16. data/lib/toaster/model/automation_run.rb +2 -11
  17. data/lib/toaster/model/key_value_pair.rb +13 -1
  18. data/lib/toaster/model/task.rb +3 -3
  19. data/lib/toaster/model/task_execution.rb +3 -2
  20. data/lib/toaster/model/task_parameter.rb +17 -24
  21. data/lib/toaster/state/convergence.rb +2 -2
  22. data/lib/toaster/state/idempotence.rb +13 -7
  23. data/lib/toaster/state/system_state.rb +1 -0
  24. data/lib/toaster/test/test_case.rb +10 -5
  25. data/lib/toaster/test/test_runner.rb +131 -124
  26. data/lib/toaster/test/test_suite.rb +1 -1
  27. data/lib/toaster/test_manager.rb +3 -9
  28. data/lib/toaster/toaster_app_service.rb +0 -4
  29. data/lib/toaster/util/config.rb +6 -1
  30. data/lib/toaster/util/lxc.rb +1 -1
  31. data/webapp/app/assets/javascripts/jstree.util.js +2 -1
  32. data/webapp/app/assets/stylesheets/application.css +21 -1
  33. data/webapp/app/assets/stylesheets/layout.css +1 -1
  34. data/webapp/app/controllers/analysis_controller.rb +12 -0
  35. data/webapp/app/controllers/application_controller.rb +11 -3
  36. data/webapp/app/controllers/base_controller.rb +1 -0
  37. data/webapp/app/controllers/execs_controller.rb +12 -4
  38. data/webapp/app/controllers/scripts_controller.rb +91 -52
  39. data/webapp/app/controllers/test_controller.rb +4 -4
  40. data/webapp/app/views/analysis/convergence.html.erb +14 -11
  41. data/webapp/app/views/analysis/idempotence.html.erb +40 -1
  42. data/webapp/app/views/analysis/index.html.erb +117 -0
  43. data/webapp/app/views/execs/automation_runs.html.erb +10 -4
  44. data/webapp/app/views/execs/task_executions.html.erb +20 -16
  45. data/webapp/app/views/layouts/application.html.erb +22 -9
  46. data/webapp/app/views/scripts/graph.html.erb +1 -1
  47. data/webapp/app/views/scripts/import_chef.html.erb +4 -0
  48. data/webapp/app/views/scripts/scripts.html.erb +5 -17
  49. data/webapp/app/views/settings/{index.html.erb → config.html.erb} +4 -6
  50. data/webapp/app/views/settings/containers.html.erb +7 -9
  51. data/webapp/app/views/test/gen.html.erb +1 -0
  52. data/webapp/app/views/test/suites.html.erb +1 -1
  53. data/webapp/app/views/util/chef.html.erb +2 -2
  54. data/webapp/config/initializers/devise.rb +4 -1
  55. data/webapp/config/routes.rb +15 -8
  56. data/webapp/log/development.log +39521 -0
  57. data/webapp/tmp/cache/assets/development/sprockets/0dc0562647e703ca0535da3b9fcad796 +0 -0
  58. data/webapp/tmp/cache/assets/development/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
  59. data/webapp/tmp/cache/assets/development/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
  60. data/webapp/tmp/cache/assets/development/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
  61. data/webapp/tmp/cache/assets/development/sprockets/72cbfd5bf33945bcce154f7a4feaf04d +0 -0
  62. data/webapp/tmp/cache/assets/development/sprockets/7b2b7d9034fc7b77daf5da1436667e6f +0 -0
  63. data/webapp/tmp/cache/assets/development/sprockets/b6f1534bcdbff92a16c85487f363235a +0 -0
  64. data/webapp/tmp/cache/assets/development/sprockets/bfac6cd2984fbd5e0d762389e3c37164 +0 -0
  65. data/webapp/tmp/cache/assets/development/sprockets/c5907cfd07b24ad19b8c80e8af618a57 +0 -0
  66. data/webapp/tmp/cache/assets/development/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
  67. data/webapp/tmp/cache/assets/development/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
  68. data/webapp/tmp/cache/assets/development/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
  69. metadata +53 -51
@@ -10,12 +10,12 @@ convs = {}
10
10
  begin
11
11
 
12
12
  show_all_link = false
13
- automation = nil
14
- if param('task') != ""
13
+ automation = cur_auto
14
+ if param('task_id') != ""
15
15
  tasks = [get_task_for_param()]
16
16
  show_all_link = true
17
- elsif param('auto') != ""
18
- automation = get_automation_for_param()
17
+ end
18
+ if automation
19
19
  tasks = automation.get_globally_executed_tasks() if automation
20
20
  end
21
21
 
@@ -31,9 +31,10 @@ end
31
31
  end
32
32
 
33
33
  %>
34
- <h2>Convergence of System State</h2>
34
+ <h1>Convergence of System State</h1>
35
35
  <form action="#" method="post">
36
36
  <% if tasks %>
37
+ Selected automation UUID: <%= automation.uuid %>
37
38
  <% if show_all_link %>
38
39
  <ul>
39
40
  <li>Currently only displaying convergence of a single task. <a href="<%= l('task' => '') %>">Show All Tasks</a>
@@ -41,7 +42,7 @@ end
41
42
  </ul>
42
43
  <% end %>
43
44
 
44
- <h3>Track State Properties</h3>
45
+ <h2>Track State Properties</h2>
45
46
  Enter state property name patterns (one per line):<br/>
46
47
  <textarea rows="3" cols="40" name="trackProps"><%=
47
48
  param("trackProps") != "" ? param("trackProps") : ".*"
@@ -60,8 +61,10 @@ end
60
61
  props << prop
61
62
  end
62
63
  exes = []
63
- traces[run][props[0]].collect do |tuple|
64
- exes << tuple[0]
64
+ if traces[run][props[0]]
65
+ traces[run][props[0]].collect do |tuple|
66
+ exes << tuple[0]
67
+ end
65
68
  end
66
69
  %>
67
70
  <table class="tablesorter"><thead><tr>
@@ -106,7 +109,7 @@ end
106
109
  post_states = Set.new(task.global_post_states_flat)
107
110
  %>
108
111
  <tr><td colspan="4">Task
109
- <b><a href="<%= l('t'=>'tasks', 'task'=>task.id) %>"><%= task.name %></a></b>
112
+ <b><a href="/scripts/<%= task.automation.id %>/tasks/<%= task.id %>"><%= task.name %></a></b>
110
113
  </td></tr>
111
114
  <%
112
115
  {"PRE-state" => pre_states,
@@ -132,9 +135,9 @@ end
132
135
  end
133
136
  %>
134
137
 
135
- <h3>State Convergence By Task</h3>
138
+ <h2>State Convergence By Task</h2>
136
139
  <% tasks.each do |task| %>
137
- <h3>State Convergence of Task '<a href="<%= l('t'=>'tasks', 'task'=>task.id) %>"><%= task.name %></a>'</h3>
140
+ <h3>State Convergence of Task '<a href="/scripts/<%= task.automation.id %>/tasks/<%= task.id %>"><%= task.name %></a>'</h3>
138
141
  <% task_convs = convs[task] ? convs[task] : []
139
142
  if task_convs.empty? %>
140
143
  No convergent state property found for this task.
@@ -1,2 +1,41 @@
1
1
  <h1>Idempotence</h1>
2
- <p>coming soon...</p>
2
+ <%
3
+
4
+ require 'toaster/state/idempotence'
5
+ require 'toaster/util/util'
6
+
7
+ auto = cur_auto
8
+ suite = cur_suite
9
+ non_idem = nil
10
+ if suite
11
+ auto = suite.automation
12
+ idem_check = Idempotence.new(suite)
13
+ non_idem = idem_check.non_idempotent_task_seq()
14
+ elsif auto
15
+ idem_check = Idempotence.new(auto)
16
+ non_idem = idem_check.non_idempotent_task_seq()
17
+ end
18
+
19
+ %>
20
+
21
+ <% if auto %>
22
+ Automation UUID: <%= auto.uuid %>
23
+ <% if suite %>
24
+ <br/>Test Suite UUID: <%= suite.uuid %>
25
+ <% end %>
26
+ <h2>Non-Idempotent Task Sequences</h2>
27
+ <table>
28
+ <thead>
29
+ <tr><th>ID</th><th>Task List</th></tr>
30
+ </thead>
31
+ <% non_idem.each_with_index do |seq,idx|
32
+ seq = seq.collect {|t|
33
+ "<a href=\"/scripts/#{t.automation.id}/tasks/#{t.id}\">#{t.resource}</a>"
34
+ }
35
+ %>
36
+ <tr><td><%= idx+1 %></td><td><%= seq.join(" &rarr; ").html_safe %></td></tr>
37
+ <% end %>
38
+ </table>
39
+ <% else %>
40
+ Please select an <b>automation</b> or a specific <b>test suite</b> to perform idempotence analysis.
41
+ <% end %>
@@ -0,0 +1,117 @@
1
+ <h1>Test Analysis</h1>
2
+ <h2>Automations</h2>
3
+ <%
4
+
5
+ require 'toaster/state/convergence'
6
+ require 'toaster/util/util'
7
+ require 'toaster/model/automation'
8
+
9
+ autos = Toaster::Automation.find()
10
+ auto = cur_auto
11
+ tasks = []
12
+ suite = suite
13
+ show_toaster_tasks = false
14
+ if cur_suite
15
+ auto = suite.automation
16
+ end
17
+ if auto
18
+ tasks = auto.tasks.to_a
19
+ end
20
+
21
+ %>
22
+
23
+ <table class="tablesorter">
24
+ <thead>
25
+ <tr>
26
+ <th>#</th><th>UUID</th><th>Name</th><th>Type</th><th>Tasks</th>
27
+ <th>Attributes</th><th>Runs</th><th>State Changes</th><th colspan="6">Actions</th></tr>
28
+ </thead>
29
+ <tbody>
30
+ <% autos.each_with_index { |row,id|
31
+ t = Time.now.to_i
32
+ active = !auto ? false : row.id == auto.id
33
+ param_auto = active ? "" : row.id
34
+ param_hash = {"auto" => param_auto, "run" => "", "task" => "", "exe" => ""}
35
+ num_runs = row.get_num_runs
36
+ globally_executed_tasks = row.get_globally_executed_tasks
37
+ prop_changes = row.num_global_state_transitions
38
+ %>
39
+ <tr class="<%= active ? "active" : "" %>">
40
+ <td><%= id+1 %></td>
41
+ <td><a href="/scripts/<%= row.id %>/details"><%= row.uuid %></a></td>
42
+ <td><%= row.name %></td>
43
+ <td><%= row.language %></td>
44
+ <td><%= globally_executed_tasks.size %></td>
45
+ <td><%= row.automation_attributes.size %></td>
46
+ <td><%= num_runs %></td>
47
+ <td><%= link_to "#{prop_changes}", "/execs/#{row.id}/tasks" %></td>
48
+ <td><%= link_to 'details', "/analysis/index/#{row.id}" %></td>
49
+ <td><%= link_to 'convergence', "/analysis/conv/auto/#{row.id}" %></td>
50
+ <td><%= link_to 'idempotence', "/analysis/idem/auto/#{row.id}" %></td>
51
+ </tr>
52
+ <% } %>
53
+ </tbody>
54
+ </table>
55
+
56
+ <% if !auto %>
57
+ Please select an <b>automation</b> or a specific <b>test suite</b> to perform idempotence analysis.
58
+ <% else %>
59
+ <h2>Automation Details</h2>
60
+ <p>Selected Automation UUID: <%= auto.uuid %></p>
61
+ <h3>Automation Tasks</h3>
62
+ <% if suite %>
63
+ <br/>Test Suite UUID: <%= suite.uuid %>
64
+ <% end %>
65
+
66
+ <table class="tablesorter" id="tablesorter">
67
+ <thead>
68
+ <tr><th>#</th><th>ID</th>
69
+ <th>Resource</th><th>Action</th>
70
+ <!--<th>File</th><th>Line</th>-->
71
+ <th>Success (%)</th>
72
+ <th>State Changes</th>
73
+ <th colspan="2">Actions</th></tr>
74
+ </thead>
75
+ <tbody>
76
+ <% count = 0
77
+ tasks.each_with_index { |row,id|
78
+ if show_toaster_tasks || !row.toaster_testing_task?
79
+ active = false
80
+ param_task = active ? "" : row.id
81
+ clazz = active ? "active " : ""
82
+ clazz.strip!
83
+ #prop_changes = row.global_state_prop_changes
84
+ prop_changes = row.global_state_transitions
85
+ %>
86
+ <tr<%= clazz != '' ? " class=\"#{clazz}\"" : "" %>>
87
+ <td><%= count += 1 %></td>
88
+ <td><%= row.uuid %></td>
89
+ <td><%= row.resource %></td>
90
+ <td><%= row.action %></td>
91
+ <!--<td><%= row.sourcefile %></td>
92
+ <td><%= row.sourceline %></td>-->
93
+ <td><%= format_float(row.global_success_percentage) %> %</td>
94
+ <td><%= prop_changes.size %></td>
95
+ <td><a href="/analysis/conv/task/<%= row.id %>">convergence</a></td>
96
+ <td><a href="/analysis/idem/task/<%= row.id %>">idempotence</a></td>
97
+ </tr>
98
+ <% end
99
+ } %>
100
+ </tbody>
101
+ </table>
102
+
103
+ <h3>All Affected State Properties</h3>
104
+ <table class="tablesorter">
105
+ <thead>
106
+ <tr><th>Property Name</th></tr>
107
+ </thead>
108
+ <% begin
109
+ auto.all_affected_property_names.each do |p| %>
110
+ <tr><td><%= p %></td></tr>
111
+ <% end
112
+ rescue => ex %>
113
+ <tr><td>[Error: <%= ex %> <%= ex.backtrace %>]</td></tr>
114
+ <% end %>
115
+ </table>
116
+
117
+ <% end %>
@@ -10,7 +10,6 @@ begin
10
10
  auto = cur_auto()
11
11
  runs = cur_runs()
12
12
  run = cur_run()
13
- puts "run #{run}"
14
13
 
15
14
  end
16
15
 
@@ -18,24 +17,26 @@ end
18
17
  <div>
19
18
  <h1>Automation Runs</h1>
20
19
 
20
+ <p>
21
21
  <ul><li>
22
- <% if auto %>
22
+ <% if auto && auto.id %>
23
23
  Displaying runs of automation <b>'<%= auto.name %>'</b>.
24
24
  (<a href="/execs">show all</a>)
25
25
  <% else %>
26
26
  Displaying runs of all automations. Use the 'Automation' section to filter the list for a specific automation.
27
27
  <% end %>
28
28
  </li></ul>
29
+ </p>
29
30
 
30
31
  <table class="tablesorter">
31
32
  <thead>
32
33
  <tr><th>#</th><th>UUID</th><th>Automation</th><th>Start Time</th><!-- <th>Machine ID</th> -->
33
- <th>Task Executions</th><th>Duration</th><th>Success</th><th colspan="2">Actions</th></tr>
34
+ <th>Task Executions</th><th>Duration</th><th>Success</th><th colspan="3">Actions</th></tr>
34
35
  </thead>
35
36
  <tbody>
36
37
  <% runs.each_with_index { |row,id|
37
38
  clazz = row.success ? 'success' : 'error'
38
- active = row.id.to_s == param('run')
39
+ active = run && row.id == run.id
39
40
  clazz += ' active' if active
40
41
  param_run = active ? "" : row.id
41
42
  auto_name = row.automation ? row.automation.name : "n/a"
@@ -52,6 +53,11 @@ param_hash = {"run" => param_run}.merge(row.automation ? {'auto' => row.automati
52
53
  <td class="center"><%= row.success ? "true" : "false" %></td>
53
54
  <td><% if row.automation %><a href="/execs/<%= row.automation.id %>/<%= row.id %>">details</a><% end %></nobr></td>
54
55
  <td><% if row.automation %><a href="/execs/<%= row.automation.id %>/<%= row.id %>/tasks">executed tasks</a><% end %></nobr></td>
56
+ <td><%= if row.automation
57
+ link_to 'delete', "/execs/#{row.automation.id}/#{row.id}",
58
+ :data => { :confirm => 'Confirm: Delete this automation run, including all task executions?'
59
+ }, :method => :delete
60
+ end %></td>
55
61
  </tr>
56
62
  <% } %>
57
63
  </tbody>
@@ -8,16 +8,16 @@ run = cur_run()
8
8
  show_toaster_tasks = true # TODO
9
9
 
10
10
  %>
11
- <h2>Task Executions</h2>
11
+ <h1>Task Executions</h1>
12
12
  <% if task
13
13
  global_executions = task.global_executions
14
14
  %>
15
- <h3>Details of Task '<%= task.name %>'</h3>
15
+ <h2>Details of Task '<%= task.name %>'</h2>
16
16
  <table>
17
17
  <tr><td>Number of executions:</td><td><%= global_executions.size %></td></tr>
18
18
  </table>
19
19
 
20
- <h4>Executions</h4>
20
+ <h3>Executions</h3>
21
21
  <table class="properties tablesorter">
22
22
  <thead>
23
23
  <tr><th>#</th><th>Automation Run</th><th>Start Time</th><th>Duration</th><th>Success</th><th>Property<br/>Changes</th><th>Actions</th></tr>
@@ -30,25 +30,30 @@ global_executions = task.global_executions
30
30
  %>
31
31
  <tr class="<%= exe.success ? 'success' : 'error' %><%= active ? ' active' : '' %>">
32
32
  <td><%= index+1 %></td>
33
- <td><a href="/execs/<%= run.automation.id %>/<%= run.id %>"><%= run.uuid %></a></td>
33
+ <td><% if run.automation %>
34
+ <a href="/execs/<%= run.automation.id %>/<%= run.id %>"><%= run.uuid %></a>
35
+ <% end %></td>
34
36
  <td><%= format_time(exe.start_time) %></td>
35
37
  <td><%= to_minutes(exe.end_time.to_i - exe.start_time) %></td>
36
38
  <td><%= exe.success %></td>
37
39
  <td><%= exe.state_changes.size %></td>
38
- <td><a href="<%= l('exe' => param_exe) %>"><%= active ? "hide" : "show" %> details</a></td>
40
+ <td><% if run.automation %>
41
+ <a href="/execs/<%= run.automation.id %>/tasks/<%= task.id %>/<%= exe.id %>">details</a>
42
+ <% end %></td>
39
43
  </tr>
40
44
  <% end %>
41
45
  </tbody>
42
46
  </table>
43
47
 
44
48
  <% if exec %>
45
- <h4>Execution Details</h4>
49
+ <h3>Execution Details</h3>
50
+ <p>Task execution UUID: <%= exec.uuid %></p>
46
51
  <% if exec.output && exec.output.strip != "" %>
47
- <h5>Script Output:</h5>
52
+ <h4>Script Output:</h4>
48
53
  <pre style="overflow: auto; height: 100px"><%= exec.output %></pre>
49
54
  <% end %>
50
55
  <% if !exec.success && exec.error_details %>
51
- <h5>Error Details:</h5>
56
+ <h4>Error Details:</h4>
52
57
  <pre style="overflow: auto; height: 250px"><%= exec.error_details %></pre>
53
58
  <% end %>
54
59
  <script type="text/javascript" src="/assets/jquery.jstree.js"></script>
@@ -57,11 +62,10 @@ global_executions = task.global_executions
57
62
  <script type="text/javascript" src="/assets/jstree.util.js"></script>
58
63
  <% if exec.state_before %>
59
64
  <div class="stateFrame">
60
- <h5>Pre-State:</h5>
65
+ <h4>Pre-State:</h4>
61
66
  <div id="preState"></div>
62
67
  </div>
63
68
  <script type="text/javascript">
64
- <%= puts exec.state_before.to_s %>
65
69
  var jsonData = <%= exec.state_before.to_json.html_safe %>
66
70
  initTree("preState", jsonData);
67
71
  </script>
@@ -69,7 +73,7 @@ global_executions = task.global_executions
69
73
  <div style="width: 5%; float: left;">&nbsp;</div>
70
74
  <% if exec.state_after %>
71
75
  <div class="stateFrame">
72
- <h5>Post-State:</h5>
76
+ <h4>Post-State:</h4>
73
77
  <div id="postState"></div>
74
78
  </div>
75
79
  <script type="text/javascript">
@@ -80,7 +84,7 @@ global_executions = task.global_executions
80
84
  <div style="clear: both"></div>
81
85
  <% end %>
82
86
 
83
- <h4>State changes</h4>
87
+ <h3>State changes</h3>
84
88
  <table id="properties" class="tablesorter">
85
89
  <thead>
86
90
  <tr><th>Action</th><th>Property</th><th colspan="3">Value(s)</th><th>Occurrences</th><th>Occurrences (%)</th></tr>
@@ -105,10 +109,10 @@ global_executions = task.global_executions
105
109
  </table>
106
110
 
107
111
  <% elsif run %>
108
-
112
+ <p>Automation run UUID: <%= run.uuid %></p>
109
113
  <table class="tablesorter" id="tablesorter">
110
114
  <thead>
111
- <tr><th>#</th><th>ID</th>
115
+ <tr><th>#</th><th>Task ID</th>
112
116
  <th>Start Time</th><th>Duration</th>
113
117
  <th>Resource</th><th>Action</th><th>File</th><th>Line</th>
114
118
  <th>Success</th>
@@ -119,7 +123,7 @@ global_executions = task.global_executions
119
123
  run.task_executions.each_with_index { |exec,id|
120
124
  row = exec.task
121
125
  if show_toaster_tasks || !row.toaster_testing_task?
122
- active = row.id.to_s == param('task')
126
+ active = task && row.id == task.id
123
127
  param_task = active ? "" : row.id
124
128
  clazz = active ? "active " : ""
125
129
  if !run && detailed
@@ -140,7 +144,7 @@ global_executions = task.global_executions
140
144
  <td><%= row.sourcefile %></td>
141
145
  <td><%= row.sourceline %></td>
142
146
  <td><%= exec.success %></td>
143
- <td><a href="/execs/<%= run.automation.id %>/tasks/<%= exec.id %>/<%= run.id %>">details</a></td>
147
+ <td><a href="/execs/<%= run.automation.id %>/tasks/<%= exec.task.id %>/<%= exec.id %>">details</a></td>
144
148
  </tr>
145
149
  <% end
146
150
  } %>
@@ -19,9 +19,6 @@
19
19
  session['db.host'] = Toaster::Config.get("db.host") if "#{session['db.host']}".empty?
20
20
  session['db.port'] = Toaster::Config.get("db.port") if "#{session['db.port']}".empty?
21
21
  %>
22
- <p class="notice"><%= notice %></p>
23
- <p class="alert"><%= alert %></p>
24
-
25
22
  <div class="container">
26
23
  <div class="header">
27
24
  <h1>ToASTER<sup>[beta]</sup></h1>
@@ -66,10 +63,10 @@
66
63
  </div>
67
64
  </a>
68
65
  <ul><li><a href="/execs">Automation Runs</a></li>
69
- <li><a href="/execs/0/tasks">Task Executions</a></li></ul>
66
+ <li><a href="/execs/tasks">Task Executions</a></li></ul>
70
67
  </li>
71
68
  <li class="<%= request.path.match(/^\/analysis/) ? "active" : "inactive" %>">
72
- <a href="/analysis/conv">
69
+ <a href="/analysis/index">
73
70
  <span class="ca-icon">L</span>
74
71
  <div class="ca-content">
75
72
  <h2 class="ca-main">Analysis</h2>
@@ -90,24 +87,40 @@
90
87
  <ul><li><a href="/util/chef">Chef</a></li></ul>
91
88
  </li>
92
89
  <li class="<%= request.path.match(/^\/settings/) ? "active" : "inactive" %>">
93
- <a href="/settings/index">
90
+ <a href="/settings/config">
94
91
  <span class="ca-icon">K</span>
95
92
  <div class="ca-content">
96
93
  <h2 class="ca-main">Settings</h2>
97
94
  <h3 class="ca-sub">Adjust configurations</h3>
98
95
  </div>
99
96
  </a>
100
- <ul><li><a href="/settings/index">Configuration</a></li>
97
+ <ul><li><a href="/settings/config">Configuration</a></li>
101
98
  <li><a href="/settings/containers">Containers</a></li></ul>
102
99
  </li>
103
100
  </ul>
104
101
 
105
102
  <div class="pages">
106
- <div id="quickstart" class="panel">
107
103
  <div class="content">
104
+ <div class="messages">
105
+ <% flash.each do |name, msg|
106
+ if msg.kind_of?(Array) && msg.size == 1
107
+ msg = msg[0]
108
+ end %>
109
+ <div class="<%= name %>">
110
+ <% if msg.kind_of?(Array) %>
111
+ <ul>
112
+ <% msg.each do |msg1| %>
113
+ <li><%= msg1 %></li>
114
+ <% end %>
115
+ </ul>
116
+ <% else %>
117
+ <%= msg %>
118
+ <% end %>
119
+ </div>
120
+ <% end %>
121
+ </div>
108
122
  <%= yield %>
109
123
  </div>
110
- </div>
111
124
  </div>
112
125
  </div>
113
126
  </body>