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
@@ -20,7 +20,7 @@ module Toaster
20
20
  belongs_to :automation
21
21
  belongs_to :user
22
22
  belongs_to :test_coverage_goal
23
- has_many :test_cases, nil, {:autosave => true, :dependent => :delete_all}
23
+ has_many :test_cases, :autosave => true, :dependent => :destroy
24
24
  serialize :parameter_test_values, JSON
25
25
 
26
26
  def initialize(attr_hash)
@@ -106,6 +106,7 @@ module Toaster
106
106
  # get additional_state_configs from automation
107
107
  automation = AutomationRun.get_current().automation
108
108
  add_automation_specific_state_config(@state_change_config)
109
+ task.automation = automation if !task.automation
109
110
 
110
111
  # determine which parameters the task code accesses:
111
112
  task.task_parameters.concat(ResourceInspector.get_accessed_parameters(task))
@@ -248,15 +249,8 @@ module Toaster
248
249
  if !test_suite.kind_of?(TestSuite)
249
250
  test_suite = TestSuite.find({"uuid" => test_suite})
250
251
  end
251
- if blocking
252
- runner = TestRunner.new(test_suite, nil, false)
253
- runner.start_test_suite(blocking)
254
- runner.stop
255
- else
256
- runner = TestRunner.new(test_suite, nil, true)
257
- runner.start_test_suite(blocking)
258
- runner.start_worker_threads()
259
- end
252
+ tests_to_run = test_suite.test_cases.select { |tc| !tc.executed? }
253
+ TestRunner.instance.execute_tests(tests_to_run, blocking)
260
254
  end
261
255
 
262
256
  private
@@ -137,9 +137,5 @@ if ARGV.include?("do_start_service")
137
137
  puts "Starting service on port #{$service_port}"
138
138
  Toaster::Config.init_db_connection()
139
139
  server = ToasterAppService.new($service_port, "0.0.0.0")
140
-
141
- # client = ToasterApp.new()
142
- # client.runtest("2285f8539f6c48873")
143
- # client.runtests("88056bebc7e384cac")
144
140
  server.start
145
141
  end
@@ -44,6 +44,9 @@ module Toaster
44
44
  end
45
45
 
46
46
  def self.init_db_connection(config=nil)
47
+ if $db_connection_initialized
48
+ return
49
+ end
47
50
  require "toaster/util/util"
48
51
  if !config || !config["mysql"]
49
52
  config = {
@@ -59,8 +62,10 @@ module Toaster
59
62
  :host => "#{config["mysql"]["host"]}".empty? ? get("db.host") : config["mysql"]["host"],
60
63
  :database => "#{config["mysql"]["database"]}".empty? ? get("db.database") : config["mysql"]["database"],
61
64
  :username => "#{config["mysql"]["username"]}".empty? ? get("db.username") : config["mysql"]["username"],
62
- :password => "#{config["mysql"]["password"]}".empty? ? get("db.password") : config["mysql"]["password"]
65
+ :password => "#{config["mysql"]["password"]}".empty? ? get("db.password") : config["mysql"]["password"],
66
+ :pool => 50 # connection pool size limit (default is 5 which is not sufficient)
63
67
  )
68
+ $db_connection_initialized = true
64
69
  else
65
70
  puts "WARN: Incorrect database connection configuration"
66
71
  end
@@ -139,7 +139,7 @@ module Toaster
139
139
  node_attributes["toaster"][key] = value
140
140
  end
141
141
  end
142
- puts "DEBUG: Chef automation #{chef_node}, node attributes: #{node_attributes.inspect}"
142
+ puts "DEBUG: Chef automation #{chef_node}, node attributes: #{MarkupUtil.to_json(node_attributes)}"
143
143
 
144
144
  run_chef(lxc, chef_node, node_attributes)
145
145
  end
@@ -1,7 +1,8 @@
1
1
  function initTree(containerID, jsonData) {
2
2
  $("#" + containerID).jstree({
3
3
  "plugins" : [
4
- "themes","json_data","ui","crrm","cookies","dnd","search","types","hotkeys","contextmenu"
4
+ //"themes",
5
+ "json_data","ui","crrm","cookies","dnd","search","types","hotkeys","contextmenu"
5
6
  ],
6
7
  "json_data" : {
7
8
  "data" : prepareTreeNode(jsonData)
@@ -18,7 +18,18 @@
18
18
  font-weight: 400;
19
19
  src: local('Dosis Regular'), local('Dosis-Regular'), url("/assets/font.woff") format('woff');
20
20
  }
21
-
21
+ div.messages div {
22
+ width: 90%; margin: auto;
23
+ padding: 7px;
24
+ }
25
+ div.messages .info, div.messages .notice {
26
+ border: 1px solid #F7DF8D;
27
+ background: #FAEDC1;
28
+ }
29
+ div.messages .warn, div.messages .alert, div.messages .error {
30
+ border: 1px solid #FBA3A3;
31
+ background: #FFD4D4;
32
+ }
22
33
  .content table {
23
34
  border: 1px solid #bbc;
24
35
  }
@@ -46,4 +57,13 @@
46
57
  .content .unremarkable, .content .unremarkable td {
47
58
  opacity: 0.7;
48
59
  -moz-opacity: 0.7;
60
+ }
61
+ tr.active td {
62
+ font-weight: bold;
63
+ }
64
+ .content pre {
65
+ border: 1px solid #dddddd;
66
+ background: #f1f1f1;
67
+ font-size: 12px;
68
+ margin: 10px;
49
69
  }
@@ -110,7 +110,7 @@ h1 {
110
110
  }
111
111
  .panel:target, .pages > :last-child {
112
112
  position: absolute;
113
- left: 300px;
113
+ left: 250px;
114
114
  opacity: 1;
115
115
  -webkit-transition: opacity 200ms ease-in;
116
116
  -moz-transition: opacity 200ms ease-in;
@@ -1,7 +1,19 @@
1
1
  class AnalysisController < ApplicationController
2
+
3
+ skip_before_action :verify_authenticity_token
4
+
2
5
  def idempotence
3
6
  end
4
7
 
5
8
  def convergence
6
9
  end
10
+
11
+ def cur_auto()
12
+ ScriptsController.cur_auto(session, params)
13
+ end
14
+ def cur_suite
15
+ TestController.cur_suite(session, params)
16
+ end
17
+
18
+ helper_method :cur_auto, :cur_suite
7
19
  end
@@ -5,10 +5,18 @@ class ApplicationController < BaseController
5
5
  # For APIs, you may want to use :null_session instead.
6
6
  protect_from_forgery :with => :exception
7
7
 
8
- # use authentication based on "devise"
9
- before_filter :authenticate_user!
10
-
11
8
  # global requires
12
9
  $LOAD_PATH << File.join(File.dirname(__FILE__), "../../../../../lib")
13
10
 
11
+ # use authentication based on "devise"
12
+ #before_filter :authenticate_user!
13
+ include Devise::Controllers::Helpers
14
+ before_filter do
15
+ fail "bad ancestor" unless self.kind_of?(Devise::Controllers::Helpers)
16
+ fail "no mapping" unless Devise.class_variable_get(:@@mappings)[:user]
17
+ authenticate_user!
18
+ end
19
+
20
+ #acts_as_token_authentication_handler_for User, :fallback_to_devise => false
21
+
14
22
  end
@@ -1,3 +1,4 @@
1
+
1
2
  class BaseController < ActionController::Base
2
3
 
3
4
  def l(hash=nil)
@@ -10,9 +10,17 @@ class ExecsController < ApplicationController
10
10
  end
11
11
 
12
12
  def list
13
-
14
13
  end
15
14
 
15
+ def delete_run
16
+ run = cur_run
17
+ if run
18
+ run.destroy
19
+ msg = "Successfully deleted automation run with UUID '#{run.uuid}'"
20
+ flash[:notice] ? (flash[:notice] << msg) : (flash[:notice] = [msg])
21
+ end
22
+ redirect_to "/execs"
23
+ end
16
24
 
17
25
  def cur_auto()
18
26
  ScriptsController.cur_auto(session, params)
@@ -26,9 +34,9 @@ class ExecsController < ApplicationController
26
34
  end
27
35
  end
28
36
 
29
- def cur_run()
30
- ExecsController.cur_run(session, params)
31
- end
37
+ def cur_run()
38
+ ExecsController.cur_run(session, params)
39
+ end
32
40
  def self.cur_run(session, params)
33
41
  a = ScriptsController.cur_auto(session, params)
34
42
  return nil if !a
@@ -1,6 +1,7 @@
1
1
  class ScriptsController < ApplicationController
2
2
 
3
- require "toaster/model/automation"
3
+ require "toaster/model/automation"
4
+ require "toaster/model/key_value_pair"
4
5
  require "toaster/model/automation_attribute"
5
6
  require "toaster/chef/chef_util"
6
7
 
@@ -14,9 +15,11 @@ class ScriptsController < ApplicationController
14
15
  if request.post? || request.patch?
15
16
  if params[:add_param]
16
17
  auto = cur_auto
18
+ set_auto_values(auto)
17
19
  auto.automation_attributes << Toaster::AutomationAttribute.new(
18
20
  :key => "", :value => "")
19
21
  elsif params[:del_param]
22
+ set_auto_values(auto)
20
23
  params[:auto][:attr].each do |index,attr|
21
24
  if params[:del_param][index]
22
25
  to_delete = cur_auto.automation_attributes[index.to_i - 1]
@@ -26,9 +29,11 @@ class ScriptsController < ApplicationController
26
29
  end
27
30
  elsif params[:add_ignoreprop]
28
31
  auto = cur_auto
32
+ set_auto_values(auto)
29
33
  auto.ignore_properties << Toaster::IgnoreProperty.new(
30
34
  :key => "", :value => "")
31
35
  elsif params[:del_ignoreprop]
36
+ set_auto_values(auto)
32
37
  params[:auto][:ignoreprop].each do |index,attr|
33
38
  if params[:del_ignoreprop][index]
34
39
  to_delete = cur_auto.ignore_properties[index.to_i - 1]
@@ -38,13 +43,16 @@ class ScriptsController < ApplicationController
38
43
  end
39
44
  elsif params[:add_additionalprop]
40
45
  auto = cur_auto
46
+ set_auto_values(auto)
41
47
  auto.additional_properties << Toaster::AdditionalProperty.new(
42
48
  :key => "", :value => "")
43
49
  elsif params[:del_additionalprop]
50
+ auto = cur_auto
51
+ set_auto_values(auto)
44
52
  params[:auto][:additionalprop].each do |index,attr|
45
53
  if params[:del_additionalprop][index]
46
- to_delete = cur_auto.additional_properties[index.to_i - 1]
47
- cur_auto.additional_properties.destroy(to_delete) if to_delete
54
+ to_delete = auto.additional_properties[index.to_i - 1]
55
+ auto.additional_properties.destroy(to_delete) if to_delete
48
56
  break
49
57
  end
50
58
  end
@@ -57,27 +65,7 @@ class ScriptsController < ApplicationController
57
65
  else
58
66
  auto = cur_auto
59
67
  end
60
- auto.name = params[:auto][:name]
61
- auto.language = params[:auto][:language]
62
- auto.visibility = params[:auto][:visibility]
63
- auto.user = current_user
64
- auto.script = params[:auto][:script]
65
- if params[:auto][:attr]
66
- params[:auto][:attr].each do |index,attr|
67
- auto.automation_attributes[index.to_i - 1].key = attr["key"]
68
- auto.automation_attributes[index.to_i - 1].value = attr["value"]
69
- end
70
- end
71
- if params[:auto][:ignoreprop]
72
- params[:auto][:ignoreprop].each do |index,prop|
73
- auto.ignore_properties[index.to_i - 1].key = prop["key"]
74
- end
75
- end
76
- if params[:auto][:additionalprop]
77
- params[:auto][:additionalprop].each do |index,prop|
78
- auto.additional_properties[index.to_i - 1].key = prop["key"]
79
- end
80
- end
68
+ set_auto_values(auto)
81
69
  auto.save
82
70
  redirect_to scripts_url()
83
71
  end
@@ -86,11 +74,35 @@ class ScriptsController < ApplicationController
86
74
  end
87
75
  end
88
76
 
77
+ def set_auto_values(auto)
78
+ auto.name = params[:auto][:name]
79
+ auto.language = params[:auto][:language]
80
+ auto.visibility = params[:auto][:visibility]
81
+ auto.user = current_user
82
+ auto.script = params[:auto][:script]
83
+ if params[:auto][:attr]
84
+ params[:auto][:attr].each do |index,attr|
85
+ auto.automation_attributes[index.to_i - 1].key = attr["key"]
86
+ auto.automation_attributes[index.to_i - 1].value = attr["value"]
87
+ end
88
+ end
89
+ if params[:auto][:ignoreprop]
90
+ params[:auto][:ignoreprop].each do |index,prop|
91
+ auto.ignore_properties[index.to_i - 1].key = prop["key"]
92
+ end
93
+ end
94
+ if params[:auto][:additionalprop]
95
+ params[:auto][:additionalprop].each do |index,prop|
96
+ auto.additional_properties[index.to_i - 1].key = prop["key"]
97
+ end
98
+ end
99
+ end
100
+
89
101
  def delete
90
102
  id = params[:auto_id]
91
103
  a = Toaster::Automation.find(id)
92
104
  if a
93
- a.delete
105
+ a.destroy
94
106
  end
95
107
  redirect_to scripts_url()
96
108
  end
@@ -107,44 +119,71 @@ class ScriptsController < ApplicationController
107
119
  :user => current_user,
108
120
  :script => script_file
109
121
  )
110
- #puts "params[:recipes].split(/[\s,;]+/) #{params[:recipes].split(/[\s,;]+/)}"
122
+ # get recipes
111
123
  params[:recipes].split(/[\s,;]+/).each do |rec|
112
- recipe_info = ChefUtil.parse_resources(
113
- params[:cookbook], rec, params[:cookbook_version])[params[:cookbook]][rec]
114
- recipe_info["resources"].each do |line,code|
115
- action = "__action__"
116
- resource = "__resource__"
117
- if recipe_info["resource_objs"][line]
118
- action = recipe_info["resource_objs"][line].action
119
- action = action.join(" , ") if action.kind_of?(Array)
120
- resource = recipe_info["resource_objs"][line].resource_name
121
- end
122
- task = Task.new(
123
- :automation => a,
124
- :sourceline => line,
125
- :sourcecode => code,
126
- :sourcefile => recipe_info["file"],
127
- :resource => resource,
128
- :action => action
129
- )
130
- task.save
131
- a.tasks << task
132
- end
133
- end
134
- a.save
135
- redirect_to scripts_url()
124
+ begin
125
+ recipe_info = ChefUtil.parse_resources(
126
+ params[:cookbook], rec, params[:cookbook_version])[params[:cookbook]][rec]
127
+ # get recipe parameters
128
+ insp = ChefNodeInspector.new { |level, msg|
129
+ if flash[:notice]
130
+ flash[:notice].concat(msg)
131
+ else
132
+ flash[:notice] = [msg]
133
+ end
134
+ }
135
+ attr_hash = insp.get_defaults(params[:cookbook], rec)
136
+ a.automation_attributes.concat(
137
+ KeyValuePair.flat_attributes_from_hash(
138
+ attr_hash, AutomationAttribute))
139
+
140
+ recipe_info["resources"].each do |line,code|
141
+ action = "__action__"
142
+ resource = "__resource__"
143
+ if recipe_info["resource_objs"][line]
144
+ action = recipe_info["resource_objs"][line].action
145
+ action = action.join(" , ") if action.kind_of?(Array)
146
+ resource = recipe_info["resource_objs"][line].to_s
147
+ end
148
+ task = Task.new(
149
+ :automation => a,
150
+ :sourceline => line,
151
+ :sourcecode => code,
152
+ :sourcefile => recipe_info["file"],
153
+ :resource => resource,
154
+ :action => action
155
+ )
156
+ # get task parameters
157
+ task.task_parameters = ResourceInspector.get_accessed_parameters(task)
158
+ # save
159
+ task.save
160
+ a.tasks << task
161
+ end
162
+ # save
163
+ a.save
164
+ rescue Object => ex
165
+ msg = "WARN: Unable to import Chef cookbook '#{params[:cookbook]}', " +
166
+ "version '#{params[:cookbook_version]}', recipe '#{rec}': #{ex}"
167
+ flash[:alert] = msg
168
+ puts msg
169
+ puts ex.backtrace.join("\n")
170
+ end
171
+ end
172
+ redirect_to scripts_url()
136
173
  end
137
174
  end
138
175
 
139
176
  def cur_auto_reset()
140
- session[:auto_cur] = nil
177
+ session[:auto_cur] = nil
141
178
  end
142
179
 
143
180
  def cur_auto()
144
181
  ScriptsController.cur_auto(session, params)
145
182
  end
146
183
  def self.cur_auto(session, params)
147
- if !session[:auto_cur] || "#{session[:auto_cur].id}" != params[:auto_id]
184
+ if !session[:auto_cur] || (
185
+ session[:auto_cur].id && "#{session[:auto_cur].id}" != params[:auto_id])
186
+
148
187
  session[:auto_cur] = nil
149
188
  if params[:auto_id] == "0"
150
189
  session[:auto_cur] = Toaster::Automation.new(
@@ -57,8 +57,9 @@ class TestController < ApplicationController
57
57
  test_case.start_time = nil
58
58
  test_case.end_time = nil
59
59
  if test_case.automation_run
60
- test_case.automation_run.delete
60
+ test_case.automation_run.destroy
61
61
  end
62
+ test_case.executing_host = nil
62
63
  test_case.save
63
64
  redirect_to "/test/suites/#{test_case.test_suite.id}"
64
65
  else
@@ -79,16 +80,15 @@ class TestController < ApplicationController
79
80
  test_suite = cur_suite
80
81
  client = service_client
81
82
  session[:suite_cur] = nil
82
- client.runtests(test_suite.uuid)
83
+ session[:exec_output] = client.runtests(test_suite.uuid)
83
84
  redirect_to "/test/suites/#{params["suite_id"]}"
84
85
  end
85
86
 
86
87
  def delete_suite
87
- puts "deleting suite ..."
88
88
  if cur_suite
89
89
  puts "deleting suite #{cur_suite}"
90
90
  session[:suite_cur] = nil
91
- cur_suite.delete
91
+ cur_suite.destroy
92
92
  redirect_to "/test/suites"
93
93
  end
94
94
  end