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
@@ -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