virtualmonkey 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +77 -0
- data/Rakefile +51 -0
- data/VERSION +1 -0
- data/bin/grinder +102 -0
- data/bin/mcicp +46 -0
- data/bin/monkey +12 -0
- data/bin/vary_instance_types +59 -0
- data/config/cloud_variables/all_clouds.json +30 -0
- data/config/cloud_variables/east.json +9 -0
- data/config/cloud_variables/rackspace.json +7 -0
- data/config/cloud_variables/west.json +9 -0
- data/config/common_inputs/apache_haproxy.json +27 -0
- data/config/common_inputs/base.json +5 -0
- data/config/common_inputs/ebs_toolbox.json +10 -0
- data/config/common_inputs/haproxy.json +15 -0
- data/config/common_inputs/lamp.json +30 -0
- data/config/common_inputs/mysql.json +24 -0
- data/config/common_inputs/none.json +4 -0
- data/config/common_inputs/php.json +25 -0
- data/config/common_inputs/php_aio_trial_chef_alpha.json +3 -0
- data/config/common_inputs/php_app_fe_chef.json +12 -0
- data/config/common_inputs/php_elb.json +12 -0
- data/config/common_inputs/qstart.json +5 -0
- data/config/common_inputs/rails.json +31 -0
- data/config/common_inputs/rails_aio_demo_chef_alpha.json +3 -0
- data/config/common_inputs/rails_aio_developer_chef_alpha.json +10 -0
- data/config/common_inputs/rsgrid.json +10 -0
- data/config/common_inputs/tomcat.json +15 -0
- data/config/common_inputs/windows_blog_engine.json +3 -0
- data/config/common_inputs/windows_net_aio.json +14 -0
- data/config/troop/11H1/backup/base.json +10 -0
- data/config/troop/11H1/backup/lamp_mysql_50.json +10 -0
- data/config/troop/11H1/backup/lamp_mysql_51.json +10 -0
- data/config/troop/11H1/backup/loadbalancer-php.json +13 -0
- data/config/troop/11H1/backup/loadbalancer.json +14 -0
- data/config/troop/11H1/backup/loadbalancer_rails.json +13 -0
- data/config/troop/11H1/backup/loadbalancer_tomcat6.json +13 -0
- data/config/troop/11H1/backup/mysql50.json +11 -0
- data/config/troop/11H1/backup/mysql50_toolbox.json +12 -0
- data/config/troop/11H1/backup/mysql51.json +11 -0
- data/config/troop/11H1/backup/mysql51_toolbox.json +12 -0
- data/config/troop/11H1/backup/php_elb.json +11 -0
- data/config/troop/11H1/base.json +10 -0
- data/config/troop/11H1/ebs_toolbox.json +12 -0
- data/config/troop/11H1/lamp_mysql_50.json +10 -0
- data/config/troop/11H1/lamp_mysql_51.json +10 -0
- data/config/troop/11H1/loadbalancer-php.json +13 -0
- data/config/troop/11H1/loadbalancer.json +17 -0
- data/config/troop/11H1/loadbalancer_rails.json +13 -0
- data/config/troop/11H1/loadbalancer_tomcat6.json +13 -0
- data/config/troop/11H1/mysql50.json +11 -0
- data/config/troop/11H1/mysql50_toolbox.json +12 -0
- data/config/troop/11H1/mysql51.json +11 -0
- data/config/troop/11H1/mysql51_awsdns.json +11 -0
- data/config/troop/11H1/mysql51_debug.json +11 -0
- data/config/troop/11H1/mysql51_toolbox.json +12 -0
- data/config/troop/11H1/php.json +13 -0
- data/config/troop/11H1/php_elb.json +11 -0
- data/config/troop/11H1/rails.json +13 -0
- data/config/troop/11H1/tomcat6.json +13 -0
- data/config/troop/chef_quickstart.json +10 -0
- data/config/troop/just_elb +10 -0
- data/config/troop/lamp_v4.json +10 -0
- data/config/troop/patch_test.json +10 -0
- data/config/troop/rightlink.json +10 -0
- data/config/troop/simple_fail.json +11 -0
- data/config/troop/simple_pass.json +11 -0
- data/config/troop/windows_blog_engine.json +10 -0
- data/config/troop/windows_net_aio.json +10 -0
- data/config/troop/windows_quick_start.json +10 -0
- data/features/base.rb +31 -0
- data/features/db_toolbox.rb +59 -0
- data/features/ebs_toolbox.rb +62 -0
- data/features/lamp.rb +33 -0
- data/features/lb-apache-haproxy.rb +49 -0
- data/features/mysql_5.x_v2_v4_from_scratch.rb +71 -0
- data/features/mysql_5.x_v2_v4_from_scratch_awsdns.rb +71 -0
- data/features/mysql_5.x_v2_v4_from_scratch_dyndns.rb +71 -0
- data/features/mysql_v1_upgrade_v2.rb +54 -0
- data/features/old_cuke_features/Rakefile +121 -0
- data/features/old_cuke_features/Steps-TODO +31 -0
- data/features/old_cuke_features/app_state.feature +25 -0
- data/features/old_cuke_features/app_test.feature +24 -0
- data/features/old_cuke_features/base.feature +16 -0
- data/features/old_cuke_features/chef_quickstart.feature +11 -0
- data/features/old_cuke_features/db_toolbox.feature +38 -0
- data/features/old_cuke_features/ebs_toolbox.feature +39 -0
- data/features/old_cuke_features/elb_create_delete.feature +41 -0
- data/features/old_cuke_features/elb_generic.feature +27 -0
- data/features/old_cuke_features/fe_app_checks.feature +21 -0
- data/features/old_cuke_features/just-start.feature +13 -0
- data/features/old_cuke_features/lamp.feature +15 -0
- data/features/old_cuke_features/lb-apache-haproxy.feature +27 -0
- data/features/old_cuke_features/mysql_5.x_v2_v4_from_scratch.feature +33 -0
- data/features/old_cuke_features/mysql_5.x_v2_v4_from_scratch_awsdns.feature +33 -0
- data/features/old_cuke_features/mysql_5.x_v2_v4_from_scratch_dyndns.feature +33 -0
- data/features/old_cuke_features/mysql_chef_premium.feature +27 -0
- data/features/old_cuke_features/mysql_chef_premium_from_scratch.feature +37 -0
- data/features/old_cuke_features/mysql_v1_upgrade_v2.feature +42 -0
- data/features/old_cuke_features/php.feature +27 -0
- data/features/old_cuke_features/php_aio_trial_chef_alpha.feature +11 -0
- data/features/old_cuke_features/php_chef.feature +21 -0
- data/features/old_cuke_features/php_elb.feature +41 -0
- data/features/old_cuke_features/rails.feature +26 -0
- data/features/old_cuke_features/rails_aio_developer_chef.feature +17 -0
- data/features/old_cuke_features/reboot.feature +23 -0
- data/features/old_cuke_features/rightlink.feature +19 -0
- data/features/old_cuke_features/rsgrid.feature +19 -0
- data/features/old_cuke_features/simple.feature +8 -0
- data/features/old_cuke_features/simple_fail.feature +9 -0
- data/features/old_cuke_features/start-stop.feature +13 -0
- data/features/old_cuke_features/step_definitions/app.rb +21 -0
- data/features/old_cuke_features/step_definitions/deployment_steps.rb +112 -0
- data/features/old_cuke_features/step_definitions/ebs.rb +36 -0
- data/features/old_cuke_features/step_definitions/elb.rb +35 -0
- data/features/old_cuke_features/step_definitions/lb.rb +22 -0
- data/features/old_cuke_features/step_definitions/mysql_steps.rb +84 -0
- data/features/old_cuke_features/terminate.feature +7 -0
- data/features/old_cuke_features/tomcat6-tests-TODO +29 -0
- data/features/old_cuke_features/tomcat6.feature +27 -0
- data/features/patch_test.rb +33 -0
- data/features/php.rb +54 -0
- data/features/php_elb.rb +78 -0
- data/features/rails.rb +54 -0
- data/features/start_only.rb +26 -0
- data/features/tomcat6.rb +54 -0
- data/lib/virtualmonkey.rb +28 -0
- data/lib/virtualmonkey/application.rb +75 -0
- data/lib/virtualmonkey/application_frontend.rb +42 -0
- data/lib/virtualmonkey/command.rb +39 -0
- data/lib/virtualmonkey/command/clone.rb +50 -0
- data/lib/virtualmonkey/command/create.rb +21 -0
- data/lib/virtualmonkey/command/destroy.rb +51 -0
- data/lib/virtualmonkey/command/list.rb +10 -0
- data/lib/virtualmonkey/command/run.rb +76 -0
- data/lib/virtualmonkey/command/troop.rb +146 -0
- data/lib/virtualmonkey/cuke_monk.rb +184 -0
- data/lib/virtualmonkey/deployment_monk.rb +132 -0
- data/lib/virtualmonkey/deployment_runner.rb +333 -0
- data/lib/virtualmonkey/ebs.rb +161 -0
- data/lib/virtualmonkey/ebs_runner.rb +59 -0
- data/lib/virtualmonkey/elb_runner.rb +194 -0
- data/lib/virtualmonkey/fe_app_runner.rb +7 -0
- data/lib/virtualmonkey/file_locations.rb +7 -0
- data/lib/virtualmonkey/frontend.rb +124 -0
- data/lib/virtualmonkey/http_checks.rb +33 -0
- data/lib/virtualmonkey/index.html.erb +109 -0
- data/lib/virtualmonkey/lamp_runner.rb +29 -0
- data/lib/virtualmonkey/mysql.rb +172 -0
- data/lib/virtualmonkey/mysql_runner.rb +108 -0
- data/lib/virtualmonkey/mysql_toolbox_runner.rb +51 -0
- data/lib/virtualmonkey/patch_runner.rb +46 -0
- data/lib/virtualmonkey/php_aio_trial_chef_runner.rb +6 -0
- data/lib/virtualmonkey/php_chef_runner.rb +69 -0
- data/lib/virtualmonkey/rails_aio_developer_chef_runner.rb +8 -0
- data/lib/virtualmonkey/shared_dns.rb +67 -0
- data/lib/virtualmonkey/simple.rb +5 -0
- data/lib/virtualmonkey/simple_runner.rb +6 -0
- data/lib/virtualmonkey/test_case_interface.rb +151 -0
- data/lib/virtualmonkey/unified_application.rb +40 -0
- data/spec/bug3518.rb +16 -0
- data/spec/concurrent_writes_spec.rb +26 -0
- data/spec/cuke_job_spec.rb +26 -0
- data/spec/ek.rb +28 -0
- data/spec/little_ruby.rb +20 -0
- data/spec/mini.rb +25 -0
- data/spec/monitoring.rb +13 -0
- data/spec/release_aws_dns.rb +5 -0
- data/spec/release_dns.rb +5 -0
- data/spec/release_dyndns.rb +5 -0
- data/spec/shared_resources_spec.rb +25 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/virtualmonkey_spec.rb +7 -0
- data/virtualmonkey.gemspec +265 -0
- 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
|