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