virtualmonkey 0.0.1

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 (178) hide show
  1. data/.document +5 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +77 -0
  4. data/Rakefile +51 -0
  5. data/VERSION +1 -0
  6. data/bin/grinder +102 -0
  7. data/bin/mcicp +46 -0
  8. data/bin/monkey +12 -0
  9. data/bin/vary_instance_types +59 -0
  10. data/config/cloud_variables/all_clouds.json +30 -0
  11. data/config/cloud_variables/east.json +9 -0
  12. data/config/cloud_variables/rackspace.json +7 -0
  13. data/config/cloud_variables/west.json +9 -0
  14. data/config/common_inputs/apache_haproxy.json +27 -0
  15. data/config/common_inputs/base.json +5 -0
  16. data/config/common_inputs/ebs_toolbox.json +10 -0
  17. data/config/common_inputs/haproxy.json +15 -0
  18. data/config/common_inputs/lamp.json +30 -0
  19. data/config/common_inputs/mysql.json +24 -0
  20. data/config/common_inputs/none.json +4 -0
  21. data/config/common_inputs/php.json +25 -0
  22. data/config/common_inputs/php_aio_trial_chef_alpha.json +3 -0
  23. data/config/common_inputs/php_app_fe_chef.json +12 -0
  24. data/config/common_inputs/php_elb.json +12 -0
  25. data/config/common_inputs/qstart.json +5 -0
  26. data/config/common_inputs/rails.json +31 -0
  27. data/config/common_inputs/rails_aio_demo_chef_alpha.json +3 -0
  28. data/config/common_inputs/rails_aio_developer_chef_alpha.json +10 -0
  29. data/config/common_inputs/rsgrid.json +10 -0
  30. data/config/common_inputs/tomcat.json +15 -0
  31. data/config/common_inputs/windows_blog_engine.json +3 -0
  32. data/config/common_inputs/windows_net_aio.json +14 -0
  33. data/config/troop/11H1/backup/base.json +10 -0
  34. data/config/troop/11H1/backup/lamp_mysql_50.json +10 -0
  35. data/config/troop/11H1/backup/lamp_mysql_51.json +10 -0
  36. data/config/troop/11H1/backup/loadbalancer-php.json +13 -0
  37. data/config/troop/11H1/backup/loadbalancer.json +14 -0
  38. data/config/troop/11H1/backup/loadbalancer_rails.json +13 -0
  39. data/config/troop/11H1/backup/loadbalancer_tomcat6.json +13 -0
  40. data/config/troop/11H1/backup/mysql50.json +11 -0
  41. data/config/troop/11H1/backup/mysql50_toolbox.json +12 -0
  42. data/config/troop/11H1/backup/mysql51.json +11 -0
  43. data/config/troop/11H1/backup/mysql51_toolbox.json +12 -0
  44. data/config/troop/11H1/backup/php_elb.json +11 -0
  45. data/config/troop/11H1/base.json +10 -0
  46. data/config/troop/11H1/ebs_toolbox.json +12 -0
  47. data/config/troop/11H1/lamp_mysql_50.json +10 -0
  48. data/config/troop/11H1/lamp_mysql_51.json +10 -0
  49. data/config/troop/11H1/loadbalancer-php.json +13 -0
  50. data/config/troop/11H1/loadbalancer.json +17 -0
  51. data/config/troop/11H1/loadbalancer_rails.json +13 -0
  52. data/config/troop/11H1/loadbalancer_tomcat6.json +13 -0
  53. data/config/troop/11H1/mysql50.json +11 -0
  54. data/config/troop/11H1/mysql50_toolbox.json +12 -0
  55. data/config/troop/11H1/mysql51.json +11 -0
  56. data/config/troop/11H1/mysql51_awsdns.json +11 -0
  57. data/config/troop/11H1/mysql51_debug.json +11 -0
  58. data/config/troop/11H1/mysql51_toolbox.json +12 -0
  59. data/config/troop/11H1/php.json +13 -0
  60. data/config/troop/11H1/php_elb.json +11 -0
  61. data/config/troop/11H1/rails.json +13 -0
  62. data/config/troop/11H1/tomcat6.json +13 -0
  63. data/config/troop/chef_quickstart.json +10 -0
  64. data/config/troop/just_elb +10 -0
  65. data/config/troop/lamp_v4.json +10 -0
  66. data/config/troop/patch_test.json +10 -0
  67. data/config/troop/rightlink.json +10 -0
  68. data/config/troop/simple_fail.json +11 -0
  69. data/config/troop/simple_pass.json +11 -0
  70. data/config/troop/windows_blog_engine.json +10 -0
  71. data/config/troop/windows_net_aio.json +10 -0
  72. data/config/troop/windows_quick_start.json +10 -0
  73. data/features/base.rb +31 -0
  74. data/features/db_toolbox.rb +59 -0
  75. data/features/ebs_toolbox.rb +62 -0
  76. data/features/lamp.rb +33 -0
  77. data/features/lb-apache-haproxy.rb +49 -0
  78. data/features/mysql_5.x_v2_v4_from_scratch.rb +71 -0
  79. data/features/mysql_5.x_v2_v4_from_scratch_awsdns.rb +71 -0
  80. data/features/mysql_5.x_v2_v4_from_scratch_dyndns.rb +71 -0
  81. data/features/mysql_v1_upgrade_v2.rb +54 -0
  82. data/features/old_cuke_features/Rakefile +121 -0
  83. data/features/old_cuke_features/Steps-TODO +31 -0
  84. data/features/old_cuke_features/app_state.feature +25 -0
  85. data/features/old_cuke_features/app_test.feature +24 -0
  86. data/features/old_cuke_features/base.feature +16 -0
  87. data/features/old_cuke_features/chef_quickstart.feature +11 -0
  88. data/features/old_cuke_features/db_toolbox.feature +38 -0
  89. data/features/old_cuke_features/ebs_toolbox.feature +39 -0
  90. data/features/old_cuke_features/elb_create_delete.feature +41 -0
  91. data/features/old_cuke_features/elb_generic.feature +27 -0
  92. data/features/old_cuke_features/fe_app_checks.feature +21 -0
  93. data/features/old_cuke_features/just-start.feature +13 -0
  94. data/features/old_cuke_features/lamp.feature +15 -0
  95. data/features/old_cuke_features/lb-apache-haproxy.feature +27 -0
  96. data/features/old_cuke_features/mysql_5.x_v2_v4_from_scratch.feature +33 -0
  97. data/features/old_cuke_features/mysql_5.x_v2_v4_from_scratch_awsdns.feature +33 -0
  98. data/features/old_cuke_features/mysql_5.x_v2_v4_from_scratch_dyndns.feature +33 -0
  99. data/features/old_cuke_features/mysql_chef_premium.feature +27 -0
  100. data/features/old_cuke_features/mysql_chef_premium_from_scratch.feature +37 -0
  101. data/features/old_cuke_features/mysql_v1_upgrade_v2.feature +42 -0
  102. data/features/old_cuke_features/php.feature +27 -0
  103. data/features/old_cuke_features/php_aio_trial_chef_alpha.feature +11 -0
  104. data/features/old_cuke_features/php_chef.feature +21 -0
  105. data/features/old_cuke_features/php_elb.feature +41 -0
  106. data/features/old_cuke_features/rails.feature +26 -0
  107. data/features/old_cuke_features/rails_aio_developer_chef.feature +17 -0
  108. data/features/old_cuke_features/reboot.feature +23 -0
  109. data/features/old_cuke_features/rightlink.feature +19 -0
  110. data/features/old_cuke_features/rsgrid.feature +19 -0
  111. data/features/old_cuke_features/simple.feature +8 -0
  112. data/features/old_cuke_features/simple_fail.feature +9 -0
  113. data/features/old_cuke_features/start-stop.feature +13 -0
  114. data/features/old_cuke_features/step_definitions/app.rb +21 -0
  115. data/features/old_cuke_features/step_definitions/deployment_steps.rb +112 -0
  116. data/features/old_cuke_features/step_definitions/ebs.rb +36 -0
  117. data/features/old_cuke_features/step_definitions/elb.rb +35 -0
  118. data/features/old_cuke_features/step_definitions/lb.rb +22 -0
  119. data/features/old_cuke_features/step_definitions/mysql_steps.rb +84 -0
  120. data/features/old_cuke_features/terminate.feature +7 -0
  121. data/features/old_cuke_features/tomcat6-tests-TODO +29 -0
  122. data/features/old_cuke_features/tomcat6.feature +27 -0
  123. data/features/patch_test.rb +33 -0
  124. data/features/php.rb +54 -0
  125. data/features/php_elb.rb +78 -0
  126. data/features/rails.rb +54 -0
  127. data/features/start_only.rb +26 -0
  128. data/features/tomcat6.rb +54 -0
  129. data/lib/virtualmonkey.rb +28 -0
  130. data/lib/virtualmonkey/application.rb +75 -0
  131. data/lib/virtualmonkey/application_frontend.rb +42 -0
  132. data/lib/virtualmonkey/command.rb +39 -0
  133. data/lib/virtualmonkey/command/clone.rb +50 -0
  134. data/lib/virtualmonkey/command/create.rb +21 -0
  135. data/lib/virtualmonkey/command/destroy.rb +51 -0
  136. data/lib/virtualmonkey/command/list.rb +10 -0
  137. data/lib/virtualmonkey/command/run.rb +76 -0
  138. data/lib/virtualmonkey/command/troop.rb +146 -0
  139. data/lib/virtualmonkey/cuke_monk.rb +184 -0
  140. data/lib/virtualmonkey/deployment_monk.rb +132 -0
  141. data/lib/virtualmonkey/deployment_runner.rb +333 -0
  142. data/lib/virtualmonkey/ebs.rb +161 -0
  143. data/lib/virtualmonkey/ebs_runner.rb +59 -0
  144. data/lib/virtualmonkey/elb_runner.rb +194 -0
  145. data/lib/virtualmonkey/fe_app_runner.rb +7 -0
  146. data/lib/virtualmonkey/file_locations.rb +7 -0
  147. data/lib/virtualmonkey/frontend.rb +124 -0
  148. data/lib/virtualmonkey/http_checks.rb +33 -0
  149. data/lib/virtualmonkey/index.html.erb +109 -0
  150. data/lib/virtualmonkey/lamp_runner.rb +29 -0
  151. data/lib/virtualmonkey/mysql.rb +172 -0
  152. data/lib/virtualmonkey/mysql_runner.rb +108 -0
  153. data/lib/virtualmonkey/mysql_toolbox_runner.rb +51 -0
  154. data/lib/virtualmonkey/patch_runner.rb +46 -0
  155. data/lib/virtualmonkey/php_aio_trial_chef_runner.rb +6 -0
  156. data/lib/virtualmonkey/php_chef_runner.rb +69 -0
  157. data/lib/virtualmonkey/rails_aio_developer_chef_runner.rb +8 -0
  158. data/lib/virtualmonkey/shared_dns.rb +67 -0
  159. data/lib/virtualmonkey/simple.rb +5 -0
  160. data/lib/virtualmonkey/simple_runner.rb +6 -0
  161. data/lib/virtualmonkey/test_case_interface.rb +151 -0
  162. data/lib/virtualmonkey/unified_application.rb +40 -0
  163. data/spec/bug3518.rb +16 -0
  164. data/spec/concurrent_writes_spec.rb +26 -0
  165. data/spec/cuke_job_spec.rb +26 -0
  166. data/spec/ek.rb +28 -0
  167. data/spec/little_ruby.rb +20 -0
  168. data/spec/mini.rb +25 -0
  169. data/spec/monitoring.rb +13 -0
  170. data/spec/release_aws_dns.rb +5 -0
  171. data/spec/release_dns.rb +5 -0
  172. data/spec/release_dyndns.rb +5 -0
  173. data/spec/shared_resources_spec.rb +25 -0
  174. data/spec/spec.opts +1 -0
  175. data/spec/spec_helper.rb +11 -0
  176. data/spec/virtualmonkey_spec.rb +7 -0
  177. data/virtualmonkey.gemspec +265 -0
  178. metadata +428 -0
@@ -0,0 +1,146 @@
1
+ module VirtualMonkey
2
+ module Command
3
+ # This command does all the steps create/run/conditionaly destroy
4
+ def self.troop
5
+ options = Trollop::options do
6
+ text "This command performs all the operations of the monkey in one execution. Create/Run/Destroy"
7
+ opt :file, "troop config, see config/troop/*sample.json for example format", :type => :string, :required => true
8
+ opt :no_spot, "do not use spot instances"
9
+ opt :step, "use the troop config file to do either: create, run, or destroy", :type => :string
10
+ opt :tag, "add an additional tag to the deployments", :type => :string
11
+ opt :create, "interactive mode: create troop config"
12
+ opt :mci_override, "list of mcis to use instead of the ones from the server template. expects full hrefs.", :type => :string, :multi => true, :required => false
13
+ opt :no_delete, "only terminate, no deletion.", :short => "-d"
14
+ end
15
+
16
+ # PATHs SETUP
17
+ features_dir = File.join(File.dirname(__FILE__), "..", "..", "..", "features")
18
+ features_glob = Dir.glob(File.join(features_dir, "**"))
19
+ features_glob = features_glob.collect { |c| File.basename(c) }
20
+
21
+ config_dir = File.join(File.dirname(__FILE__), "..", "..", "..", "config")
22
+ cloud_variables_glob = Dir.glob(File.join(config_dir, "cloud_variables", "**"))
23
+ cloud_variables_glob = cloud_variables_glob.collect { |c| File.basename(c) }
24
+ common_inputs_glob = Dir.glob(File.join(config_dir, "common_inputs", "**"))
25
+ common_inputs_glob = common_inputs_glob.collect { |c| File.basename(c) }
26
+ global_state_dir = File.join(File.dirname(__FILE__), "..", "..", "..", "test_states")
27
+ options[:tag] += "-" if options[:tag]
28
+ options[:tag] = "" unless options[:tag]
29
+
30
+ # CREATE NEW CONFIG
31
+ if options[:create]
32
+ troop_config = {}
33
+ troop_config[:tag] = ask("What tag to use for creating the deployments?")
34
+ troop_config[:server_template_ids] = ask("What Server Template ids would you like to use to create the deployments (comma delimited)?").split(",")
35
+ troop_config[:server_template_ids].each {|st| st.strip!}
36
+
37
+ troop_config[:runner] =
38
+ choose do |menu|
39
+ menu.prompt = "What kind of deployment is this (runner type)?"
40
+ menu.choice("MysqlToolboxRunner")
41
+ menu.choice("MysqlRunner")
42
+ menu.choice("SimpleRunner")
43
+ end
44
+
45
+ troop_config[:cloud_variables] =
46
+ choose do |menu|
47
+ menu.prompt = "Which cloud_variables config file?"
48
+ menu.index = :number
49
+ menu.choices(*cloud_variables_glob)
50
+ end
51
+
52
+ troop_config[:common_inputs] =
53
+ choose do |menu|
54
+ menu.prompt = "Which common_inputs config file?"
55
+ menu.index = :number
56
+ menu.choices(*common_inputs_glob)
57
+ end
58
+
59
+ troop_config[:feature] =
60
+ choose do |menu|
61
+ menu.prompt = "Which feature file?"
62
+ menu.index = :number
63
+ menu.choices(*features_glob)
64
+ end
65
+
66
+ write_out = troop_config.to_json( :indent => " ",
67
+ :object_nl => "\n",
68
+ :array_nl => "\n" )
69
+ File.open(options[:file], "w") { |f| f.write(write_out) }
70
+ say("created config file #{options[:file]}")
71
+ say("Done.")
72
+ else
73
+ # Execute Main
74
+ config = JSON::parse(IO.read(options[:file]))
75
+ options[:step] = "all" unless options[:step]
76
+ tag = options[:tag] + config['tag']
77
+
78
+ # CREATE PHASE
79
+ if options[:step] =~ /((all)|(create))/
80
+ @dm = DeploymentMonk.new(tag, config['server_template_ids'])
81
+ @dm.variables_for_cloud = JSON::parse(IO.read(File.join(config_dir, "cloud_variables", config['cloud_variables'])))
82
+ config['common_inputs'].each do |cipath|
83
+ @dm.load_common_inputs(File.join(config_dir, "common_inputs", cipath))
84
+ end
85
+ @dm.generate_variations(options)
86
+ end
87
+
88
+ # RUN PHASE
89
+ if options[:step] =~ /((all)|(run))/
90
+ @dm = DeploymentMonk.new(tag) if options[:step] =~ /run/
91
+ EM.run {
92
+ @cm = CukeMonk.new
93
+ @cm.options = {}
94
+ remaining_jobs = @cm.jobs.dup
95
+ @dm.deployments.each do |deploy|
96
+ @cm.run_test(deploy, File.join(features_dir, config['feature']))
97
+ end
98
+
99
+ watch = EM.add_periodic_timer(10) {
100
+ @cm.watch_and_report
101
+ if @cm.all_done?
102
+ watch.cancel
103
+ end
104
+ remaining_jobs.each do |job|
105
+ # destroy on success only (keep failed deploys)
106
+ if job.status == 0 and options[:step] =~ /all/
107
+ runner = eval("VirtualMonkey::#{config['runner']}.new(job.deployment.nickname)")
108
+ puts "destroying successful deployment: #{runner.deployment.nickname}"
109
+ runner.behavior(:stop_all, false)
110
+ runner.deployment.destroy unless options[:no_delete]
111
+ remaining_jobs.delete(job)
112
+ if runner.respond_to?(:release_dns) and not options[:no_delete]
113
+ runner.behavior(:release_dns)
114
+ end
115
+ end
116
+ end
117
+ }
118
+ }
119
+ end
120
+
121
+ if options[:step] =~ /destroy/
122
+ @dm = DeploymentMonk.new(tag)
123
+ @dm.deployments.each do |deploy|
124
+ runner = eval("VirtualMonkey::#{config['runner']}.new(deploy.nickname)")
125
+ runner.behavior(:stop_all, false)
126
+ state_dir = File.join(global_state_dir, deploy.nickname)
127
+ if File.directory?(state_dir)
128
+ puts "Deleting state files for #{deploy.nickname}..."
129
+ Dir.new(state_dir).each do |state_file|
130
+ if File.extname(state_file) =~ /((rb)|(feature))/
131
+ File.delete(File.join(state_dir, state_file))
132
+ end
133
+ end
134
+ Dir.rmdir(state_dir)
135
+ end
136
+ if runner.respond_to?(:release_dns) and not options[:no_delete]
137
+ runner.behavior(:release_dns)
138
+ end
139
+ end
140
+ @dm.destroy_all unless options[:no_delete]
141
+ end
142
+ end
143
+ puts "Troop done."
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,184 @@
1
+ require 'rubygems'
2
+ require 'erb'
3
+ require 'fog'
4
+ require 'eventmachine'
5
+ require 'right_popen'
6
+
7
+ class CukeJob
8
+ attr_accessor :status, :output, :logfile, :deployment, :rest_log, :no_resume
9
+
10
+ def link_to_rightscale
11
+ i = deployment.href.split(/\//).last
12
+ d = deployment.href.split(/\./).first.split(/\//).last
13
+ "https://#{d}.rightscale.com/deployments/#{i}#auditentries"
14
+ end
15
+
16
+ def on_read_stdout(data)
17
+ # @output ||= ""
18
+ # @output << data
19
+ File.open(@logfile, "a") { |f| f.write(data) }
20
+ end
21
+
22
+ def on_read_stderr(data)
23
+ # @output ||= ""
24
+ # @output << data
25
+ File.open(@logfile, "a") { |f| f.write(data) }
26
+ end
27
+
28
+ def receive_data data
29
+ # @output += data
30
+ File.open(@logfile, "a") { |f| f.write(data) }
31
+ end
32
+
33
+ def unbind
34
+ @status = get_status.exitstatus
35
+ end
36
+
37
+ def on_exit(status)
38
+ @status = status.exitstatus
39
+ # File.open(@logfile, "a") { |f| f.write(@output) }
40
+ end
41
+
42
+ def run(deployment, cmd)
43
+ RightScale.popen3(:command => cmd,
44
+ :target => self,
45
+ :environment => {"DEPLOYMENT" => deployment.nickname,
46
+ "AWS_ACCESS_KEY_ID" => Fog.credentials[:aws_access_key_id],
47
+ "AWS_SECRET_ACCESS_KEY" => Fog.credentials[:aws_secret_access_key],
48
+ "REST_CONNECTION_LOG" => @rest_log,
49
+ "MONKEY_NO_RESUME" => "#{@no_resume}",
50
+ "MONKEY_NO_DEBUG" => "true"},
51
+ :stdout_handler => :on_read_stdout,
52
+ :stderr_handler => :on_read_stderr,
53
+ :exit_handler => :on_exit)
54
+ end
55
+ end
56
+
57
+ class CukeMonk
58
+ attr_accessor :jobs
59
+ attr_accessor :options
60
+ # Runs a cucumber test on a single Deployment
61
+ # * deployment<~String> the nickname of the deployment
62
+ # * feature<~String> the feature filename
63
+ def run_test(deployment, feature, break_point = 1000000)
64
+ new_job = CukeJob.new
65
+ new_job.logfile = File.join(@log_dir, "#{deployment.nickname}.log")
66
+ new_job.rest_log = "#{@log_dir}/#{deployment.nickname}.rest_connection.log"
67
+ new_job.deployment = deployment
68
+ new_job.no_resume = "true" if @options[:no_resume]
69
+ break_point = @options[:breakpoint] if @options[:breakpoint]
70
+ cmd = "bin/grinder #{feature} #{break_point}"
71
+ @jobs << new_job
72
+ puts "running #{cmd}"
73
+ new_job.run(deployment, cmd)
74
+ end
75
+
76
+ def initialize()
77
+ @jobs = []
78
+ @passed = []
79
+ @failed = []
80
+ @running = []
81
+ dirname = Time.now.strftime("%Y/%m/%d/%H-%M-%S")
82
+ @log_dir = File.join("log", dirname)
83
+ @log_started = dirname
84
+ FileUtils.mkdir_p(@log_dir)
85
+ @feature_dir = File.join(File.dirname(__FILE__), '..', '..', 'features')
86
+ end
87
+
88
+ # runs a feature on an array of deployments
89
+ # * deployments<~Array> array of strings containing the nicknames of the deployments
90
+ # * feature_name<~String> the feature filename
91
+ def run_tests(deployments,cmd)
92
+ deployments.each { |d| run_test(d,cmd) }
93
+ end
94
+
95
+ def watch_and_report
96
+ old_passed = @passed
97
+ old_failed = @failed
98
+ old_running = @running
99
+ old_sum = old_passed.size + old_failed.size + old_running.size
100
+ @passed = @jobs.select { |s| s.status == 0 }
101
+ @failed = @jobs.select { |s| s.status == 1 }
102
+ @running = @jobs.select { |s| s.status == nil }
103
+ new_sum = @passed.size + @failed.size + @running.size
104
+ puts "#{@passed.size} features passed. #{@failed.size} features failed. #{@running.size} features running."
105
+ if new_sum < old_sum and new_sum < @jobs.size
106
+ puts "WARNING: Jobs Lost! Finding..."
107
+ report_lost_deployments({ :old_passed => old_passed, :passed => @passed,
108
+ :old_failed => old_failed, :failed => @failed,
109
+ :old_running => old_running, :running => @running })
110
+ end
111
+ if old_passed != @passed || old_failed != @failed
112
+ status_change_hook
113
+ end
114
+ end
115
+
116
+ def status_change_hook
117
+ generate_reports
118
+ if all_done?
119
+ puts "monkey done."
120
+ EM.stop
121
+ end
122
+ end
123
+
124
+ def all_done?
125
+ running = @jobs.select { |s| s.status == nil }
126
+ running.size == 0 && @jobs.size > 0
127
+ end
128
+
129
+ def generate_reports
130
+ passed = @jobs.select { |s| s.status == 0 }
131
+ failed = @jobs.select { |s| s.status == 1 }
132
+ running = @jobs.select { |s| s.status == nil }
133
+ report_on = @jobs.select { |s| s.status == 0 || s.status == 1 }
134
+ index = ERB.new File.read(File.dirname(__FILE__)+"/index.html.erb")
135
+ bucket_name = "virtual_monkey"
136
+
137
+ ## upload to s3
138
+ # setup credentials in ~/.fog
139
+ s3 = Fog::AWS::Storage.new(:aws_access_key_id => Fog.credentials[:aws_access_key_id_test], :aws_secret_access_key => Fog.credentials[:aws_secret_access_key_test])
140
+ if directory = s3.directories.detect { |d| d.key == bucket_name }
141
+ puts "found directory, re-using"
142
+ else
143
+ directory = s3.directories.create(:key => bucket_name)
144
+ end
145
+ raise 'could not create directory' unless directory
146
+ s3.put_object(bucket_name, "#{@log_started}/index.html", index.result(binding), 'x-amz-acl' => 'public-read', 'Content-Type' => 'text/html')
147
+
148
+ report_on.each do |j|
149
+ begin
150
+ done = 0
151
+ s3.put_object(bucket_name, "#{@log_started}/#{File.basename(j.logfile)}", IO.read(j.logfile), 'Content-Type' => 'text/plain', 'x-amz-acl' => 'public-read')
152
+ s3.put_object(bucket_name, "#{@log_started}/#{File.basename(j.rest_log)}", IO.read(j.rest_log), 'Content-Type' => 'text/plain', 'x-amz-acl' => 'public-read')
153
+ done = 1
154
+ rescue Exception => e
155
+ unless e.message =~ /Bad file descriptor/i
156
+ raise e
157
+ end
158
+ sleep 1
159
+ end while not done
160
+ end
161
+
162
+ msg = <<END_OF_MESSAGE
163
+ new results avilable at http://s3.amazonaws.com/#{bucket_name}/#{@log_started}/index.html\n-OR-\nin #{@log_dir}/index.html"
164
+ END_OF_MESSAGE
165
+ puts msg
166
+ end
167
+
168
+ def report_lost_deployments(jobs = {})
169
+ running_change = jobs[:old_running] - jobs[:running]
170
+ passed_change = jobs[:passed] - jobs[:old_passed]
171
+ failed_change = jobs[:failed] - jobs[:old_failed]
172
+ lost_jobs = running_change - passed_change - failed_change
173
+ lost_jobs.each do |j|
174
+ puts "LOST JOB---------------------------------"
175
+ puts "Deployment Name: #{j.deployment.nickname}"
176
+ puts "Status Code: #{j.status}"
177
+ puts "Audit Entries: #{j.link_to_rightscale}"
178
+ puts "Log File: #{j.logfile}"
179
+ puts "Rest_Connection Log File: #{j.rest_log}"
180
+ puts "-----------------------------------------"
181
+ end
182
+ end
183
+ end
184
+
@@ -0,0 +1,132 @@
1
+ require 'rubygems'
2
+ require 'rest_connection'
3
+
4
+ class DeploymentMonk
5
+ attr_accessor :common_inputs
6
+ attr_accessor :variables_for_cloud
7
+ attr_accessor :deployments
8
+ attr_reader :tag
9
+
10
+ def from_tag
11
+ variations = Deployment.find_by(:nickname) {|n| n =~ /^#{@tag}/ }
12
+ puts "loading #{variations.size} deployments matching your tag"
13
+ return variations
14
+ end
15
+
16
+ def initialize(tag, server_templates = [], extra_images = [])
17
+ @clouds = ["1","2","3","4", "232"]
18
+ @cloud_names = { "1" => "ec2-east", "2" => "ec2-eu", "3" => "ec2-west", "4" => "ec2-ap", "232" => "rackspace"}
19
+ @tag = tag
20
+ @deployments = from_tag
21
+ @server_templates = []
22
+ @common_inputs = {}
23
+ @variables_for_cloud = {}
24
+ raise "Need either populated deployments or passed in server_template ids" if server_templates.empty? && @deployments.empty?
25
+ if server_templates.empty?
26
+ puts "loading server templates from servers in the first deployment"
27
+ @deployments.first.servers.each do |s|
28
+ server_templates << s.server_template_href.split(/\//).last.to_i
29
+ end
30
+ end
31
+ server_templates.each do |st|
32
+ @server_templates << ServerTemplate.find(st.to_i)
33
+ end
34
+
35
+ @image_count = 0
36
+ @server_templates.each do |st|
37
+ new_st = ServerTemplateInternal.new(:href => st.href)
38
+ st.multi_cloud_images = new_st.multi_cloud_images
39
+ @image_count = st.multi_cloud_images.size if st.multi_cloud_images.size > @image_count
40
+ end
41
+ end
42
+
43
+ def generate_variations(options = {})
44
+ if options[:mci_override] && !options[:mci_override].empty?
45
+ @image_count = options[:mci_override].size
46
+ end
47
+ @image_count.times do |index|
48
+ @clouds.each do |cloud|
49
+ if @variables_for_cloud[cloud] == nil
50
+ puts "variables not found for cloud #{cloud} skipping.."
51
+ next
52
+ end
53
+ dep_tempname = "#{@tag}-#{@cloud_names[cloud]}-#{rand(1000000)}-"
54
+ dep_image_list = []
55
+ new_deploy = Deployment.create(:nickname => dep_tempname)
56
+ @deployments << new_deploy
57
+ @server_templates.each do |st|
58
+ server_params = { :nickname => "tempserver-#{rand(1000000)}-#{st.nickname}",
59
+ :deployment_href => new_deploy.href,
60
+ :server_template_href => st.href,
61
+ :cloud_id => cloud
62
+ #:ec2_image_href => image['image_href'],
63
+ #:instance_type => image['aws_instance_type']
64
+ }
65
+
66
+ server = Server.create(server_params.merge(@variables_for_cloud[cloud]))
67
+ # since the create call does not set the parameters, we need to set them separate
68
+ if server.respond_to?(:set_inputs)
69
+ server.set_inputs(@variables_for_cloud[cloud]['parameters'])
70
+ else
71
+ @variables_for_cloud[cloud]['parameters'].each do |key,val|
72
+ server.set_input(key,val)
73
+ end
74
+ end
75
+
76
+ # uses a special internal call for setting the MCI on the server
77
+ if options[:mci_override] && !options[:mci_override].empty?
78
+ use_this_image = options[:mci_override][index]
79
+ dep_image_list << MultiCloudImage.find(options[:mci_override][index]).name.gsub(/ /,'_')
80
+ elsif st.multi_cloud_images[index]
81
+ dep_image_list << st.multi_cloud_images[index]['name'].gsub(/ /,'_')
82
+ use_this_image = st.multi_cloud_images[index]['href']
83
+ else
84
+ use_this_image = st.multi_cloud_images[0]['href']
85
+ end
86
+ #RsInternal.set_server_multi_cloud_image(server.href, use_this_image)
87
+ sint = ServerInternal.new(:href => server.href)
88
+ sint.set_multi_cloud_image(use_this_image)
89
+
90
+ # finally, set the spot price
91
+ unless options[:no_spot]
92
+ server.reload
93
+ server.settings
94
+ if server.ec2_instance_type =~ /small/
95
+ server.max_spot_price = "0.085"
96
+ elsif server.ec2_instance_type =~ /large/
97
+ server.max_spot_price = "0.38"
98
+ end
99
+ server.pricing = "spot"
100
+ server.parameters = {}
101
+ server.save
102
+ end
103
+ end
104
+ new_deploy.nickname = dep_tempname + dep_image_list.uniq.join("_AND_")
105
+ new_deploy.save
106
+ @common_inputs.each do |key,val|
107
+ new_deploy.set_input(key,val)
108
+ end
109
+ end
110
+ end
111
+ end
112
+
113
+ def load_common_inputs(file)
114
+ @common_inputs.merge! JSON.parse(IO.read(file))
115
+ end
116
+
117
+ def destroy_all
118
+ @deployments.each do |v|
119
+ v.reload
120
+ v.servers.each { |s| s.stop }
121
+ end
122
+ @deployments.each { |v| v.destroy }
123
+ @deployments = []
124
+ end
125
+
126
+ def get_deployments
127
+ deployments = []
128
+ @deployments.each { |v| deployments << v.nickname }
129
+ deployments
130
+ end
131
+
132
+ end