cloud-toaster 1.1.5 → 1.1.6

Sign up to get free protection for your applications and to get access to all the features.
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>