relevance_rails 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +11 -0
- data/Guardfile +7 -0
- data/Rakefile +8 -0
- data/USAGE.md +5 -4
- data/lib/generators/fixtures/fixtures_generator.rb +1 -2
- data/lib/generators/provision_config/provision_config_generator.rb +39 -31
- data/lib/generators/relevance_file/templates/Gemfile.erb +5 -2
- data/lib/relevance_rails/provision.rb +35 -108
- data/lib/relevance_rails/public_key_fetcher.rb +2 -2
- data/lib/relevance_rails/runner.rb +14 -10
- data/lib/relevance_rails/version.rb +1 -1
- data/lib/relevance_rails.rb +1 -2
- data/relevance_rails.gemspec +8 -11
- data/script/ci +6 -2
- data/script/ci_nightly +23 -7
- data/script/elzar_nightly +33 -0
- data/spec/elzar_recipes_spec.rb +88 -0
- data/spec/lib/generators/provision_config/provision_config_generator_spec.rb +116 -0
- data/spec/lib/{runner_spec.rb → relevance_rails/runner_spec.rb} +2 -3
- data/spec/spec_helper.rb +1 -0
- data/techdebt.md +7 -9
- metadata +94 -19
- data/lib/generators/provision_config/templates/authorized_keys.json.erb +0 -6
- data/lib/relevance_rails/chef_dna.rb +0 -34
- data/spec/lib/provision_config_generator_spec.rb +0 -26
- data/spec/lib/provision_spec.rb +0 -68
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
*v0.2.0*
|
2
|
+
|
3
|
+
* Depend on slushy for provisioning
|
4
|
+
* Depend on elzar as a gem
|
5
|
+
** elzar's chef recipes stay in elzar
|
6
|
+
** relevance_rails has no knowledge of elzar's recipe internals
|
7
|
+
* Search for local ssh public keys before querying ssh-agent
|
8
|
+
* Improved UX around retrying failed commands
|
9
|
+
* Fix fixtures generator
|
10
|
+
* Generated Rails app depends on haml <= 3.1.4 due to haml 3.1.5 bug
|
11
|
+
|
1
12
|
*v0.1.2*
|
2
13
|
|
3
14
|
* add streaming output from chef convergence using a fog monkeypatch
|
data/Guardfile
ADDED
data/Rakefile
CHANGED
@@ -9,3 +9,11 @@ task :acceptance do
|
|
9
9
|
ENV["ACCEPTANCE"] = "true"
|
10
10
|
Rake::Task[:spec].invoke
|
11
11
|
end
|
12
|
+
|
13
|
+
# Do not run using bundle exec!
|
14
|
+
# FakeFS causes issues when bundler injects it into the require chain.
|
15
|
+
desc 'Run the elzar nightly specs'
|
16
|
+
RSpec::Core::RakeTask.new :elzar_nightly do |t|
|
17
|
+
t.pattern = 'spec/elzar_recipes_spec.rb'
|
18
|
+
t.rspec_opts = '-t ci'
|
19
|
+
end
|
data/USAGE.md
CHANGED
@@ -13,10 +13,11 @@ $ rails g provision_config postgresql
|
|
13
13
|
Configuring bundled ssh keys
|
14
14
|
----------------------------
|
15
15
|
|
16
|
-
By default, relevance_rails bundles
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
By default, relevance_rails bundles one of your local keys (~/.ssh/id_rsa.pub, ~/.ssh/id_dsa.pub, or
|
17
|
+
~/.ssh/id_ecdsa.pub) with your instance. If none are found it bundles all your keys from `ssh-add
|
18
|
+
-L`. For bundling additional keys, you can create a ~/.relevance_rails/keys_git_url file and point it
|
19
|
+
to a git repo that has additional keys. Keys in that git repo should exist as top level *.pub files.
|
20
|
+
You *MUST* have at least one key to provision.
|
20
21
|
|
21
22
|
Provisioning on EC2
|
22
23
|
-------------------
|
@@ -11,8 +11,7 @@ STR
|
|
11
11
|
%h1 WELCOME HOME
|
12
12
|
STR
|
13
13
|
create_file "app/views/relevance_rails/db.html.haml", <<-STR
|
14
|
-
|
15
|
-
= results = conn.execute("select 4200+42 as advanced_math")
|
14
|
+
- results = ActiveRecord::Base.connection.select_all("select 4200+42 as advanced_math")
|
16
15
|
%h1.advanced_math= results.first["advanced_math"]
|
17
16
|
STR
|
18
17
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'relevance_rails'
|
2
|
+
require 'tempfile'
|
2
3
|
require 'rails/generators'
|
4
|
+
require 'elzar'
|
3
5
|
|
4
6
|
class ProvisionConfigGenerator < Rails::Generators::Base
|
5
7
|
include RelevanceRails::GeneratorOverrides
|
@@ -27,7 +29,14 @@ class ProvisionConfigGenerator < Rails::Generators::Base
|
|
27
29
|
|
28
30
|
def check_authorized_keys
|
29
31
|
if (@authorized_keys = fetch_keys).empty?
|
30
|
-
abort
|
32
|
+
abort <<-EOF
|
33
|
+
No SSH public keys were found!
|
34
|
+
|
35
|
+
To ensure you have remote access to your servers, an SSH public key must be available from at least one of these sources:
|
36
|
+
- local file (~/.ssh/id_rsa.pub, ~/.ssh/id_dsa.pub, or ~/.ssh/id_ecdsa.pub)
|
37
|
+
- ssh-agent (by running `ssh-add -L`)
|
38
|
+
- public keys git repo (URL to repo specified in ~/.relevance_rails/key_git_url)
|
39
|
+
EOF
|
31
40
|
end
|
32
41
|
end
|
33
42
|
|
@@ -39,42 +48,23 @@ class ProvisionConfigGenerator < Rails::Generators::Base
|
|
39
48
|
git :commit => '-m "Add Capistrano files"'
|
40
49
|
end
|
41
50
|
|
42
|
-
def
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
gsub_file 'provision/Vagrantfile', /config\.vm\.host_name(\s+)= .*$/,
|
47
|
-
"config.vm.host_name\\1= '#{name.gsub('_','-')}.local'"
|
48
|
-
end
|
49
|
-
|
50
|
-
def create_authorized_key_data_bag
|
51
|
-
@authorized_keys.map! {|key| "\"#{key}\""}
|
52
|
-
template('authorized_keys.json.erb', 'provision/data_bags/deploy/authorized_keys.json', {:force => true})
|
53
|
-
end
|
54
|
-
|
55
|
-
def create_dna_json
|
56
|
-
path = File.expand_path('provision/dna.json', destination_root)
|
57
|
-
json = JSON.parse File.binread(path)
|
58
|
-
json['rails_app']['name'] = name
|
59
|
-
RelevanceRails::ChefDNA.gene_splice(json,database)
|
60
|
-
create_file('provision/dna.json', JSON.generate(json), {:force => true})
|
51
|
+
def create_provision_directory
|
52
|
+
Elzar.create_provision_directory Rails.root.join('provision'),
|
53
|
+
:ruby_version => RelevanceRails.ruby_version, :database => database,
|
54
|
+
:authorized_keys => @authorized_keys, :app_name => name
|
61
55
|
end
|
62
56
|
|
63
57
|
def create_rvmrc
|
64
58
|
if File.exists?(rvmrc = Rails.root.join('.rvmrc'))
|
65
|
-
|
66
|
-
git :add => 'provision/.rvmrc'
|
59
|
+
copy_file(rvmrc, 'provision/.rvmrc', :force => true)
|
67
60
|
else
|
68
61
|
remove_file 'provision/.rvmrc'
|
69
|
-
git :rm => 'provision/.rvmrc'
|
70
62
|
end
|
71
63
|
end
|
72
64
|
|
73
65
|
def commit_changes
|
74
|
-
git :add => 'provision/
|
75
|
-
git :
|
76
|
-
git :add => 'provision/dna.json'
|
77
|
-
git :commit => '-m "Merge Elzar as our provision subdirectory"'
|
66
|
+
git :add => 'provision/'
|
67
|
+
git :commit => "-m 'Provision directory auto-created by elzar #{Elzar::VERSION}'"
|
78
68
|
end
|
79
69
|
|
80
70
|
private
|
@@ -104,10 +94,28 @@ class ProvisionConfigGenerator < Rails::Generators::Base
|
|
104
94
|
git :add => destination
|
105
95
|
end
|
106
96
|
|
107
|
-
|
108
97
|
def fetch_keys
|
109
|
-
|
110
|
-
|
111
|
-
|
98
|
+
keys = local_keys
|
99
|
+
keys = ssh_agent_keys if keys.empty?
|
100
|
+
keys += RelevanceRails::PublicKeyFetcher.public_keys
|
101
|
+
keys.uniq
|
102
|
+
end
|
103
|
+
|
104
|
+
def local_keys
|
105
|
+
key_files = [
|
106
|
+
File.expand_path("~/.ssh/id_dsa.pub"),
|
107
|
+
File.expand_path("~/.ssh/id_ecdsa.pub"),
|
108
|
+
File.expand_path("~/.ssh/id_rsa.pub"),
|
109
|
+
]
|
110
|
+
key_files.select { |p| File.exist?(p) }.take(1).map { |p| split_keys(File.read(p)) }.flatten(1)
|
111
|
+
end
|
112
|
+
|
113
|
+
def ssh_agent_keys
|
114
|
+
keys = split_keys(`ssh-add -L`)
|
115
|
+
$?.success? ? keys : []
|
116
|
+
end
|
117
|
+
|
118
|
+
def split_keys(s)
|
119
|
+
s.split("\n").reject { |k| k.blank? }
|
112
120
|
end
|
113
121
|
end
|
@@ -1,7 +1,10 @@
|
|
1
1
|
source :rubygems
|
2
2
|
|
3
3
|
gem 'rails', '~> 3.2.2'
|
4
|
-
|
4
|
+
# Avoiding 3.1.5 which has a bug with aliasing
|
5
|
+
# AbstractController::Rendering#render_to_body
|
6
|
+
# https://github.com/haml/haml/issues/519
|
7
|
+
gem 'haml', '>= 3.1.0', '<= 3.1.4'
|
5
8
|
gem 'configatron', '~> 2.8.3'
|
6
9
|
gem 'airbrake', '~> 3.0.4'
|
7
10
|
gem 'factory_girl_rails', '~> 1.2.0'
|
@@ -29,7 +32,7 @@ end
|
|
29
32
|
group "development", "test" do
|
30
33
|
gem 'capybara', '~> 1.1.1'
|
31
34
|
gem 'selenium-webdriver', '~> 2.5.0'
|
32
|
-
gem 'rspec-rails', '~> 2.
|
35
|
+
gem 'rspec-rails', '~> 2.9.0'
|
33
36
|
gem 'mocha', '~> 0.9.12'
|
34
37
|
gem 'guard-rspec', '~> 0.5.0', :require => false
|
35
38
|
gem 'growl', '~> 1.0.3', :require => false
|
@@ -1,49 +1,59 @@
|
|
1
1
|
require 'fog'
|
2
2
|
require 'thor'
|
3
|
-
require 'timeout'
|
4
3
|
require 'relevance_rails/fog_ext/ssh'
|
4
|
+
require 'slushy'
|
5
|
+
require 'elzar'
|
5
6
|
|
6
7
|
module RelevanceRails
|
7
8
|
module Provision
|
8
|
-
|
9
|
-
end
|
9
|
+
CONFIG_FILE = 'config/ec2_instance.txt'
|
10
10
|
|
11
11
|
def self.create_ec2(name = nil)
|
12
12
|
abort "Please provide a $NAME" unless name
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
slushy = provision_ec2_instances(name)
|
14
|
+
slushy.bootstrap
|
15
|
+
tmpdir = Elzar.merge_and_create_temp_directory Rails.root.join('provision')
|
16
|
+
slushy.converge tmpdir
|
17
|
+
server = slushy.server
|
18
|
+
puts "Server Instance: #{server.id}"
|
19
|
+
puts "Server IP: #{server.public_ip_address}"
|
20
|
+
server
|
16
21
|
end
|
17
22
|
|
18
23
|
def self.stop_ec2
|
19
|
-
return unless ENV["FORCE"] == "true" || Thor::Shell::Basic.new.yes?("Are you sure you want to shut down EC2 instance #{instance_id}?")
|
24
|
+
return unless (ENV["FORCE"] == "true") || Thor::Shell::Basic.new.yes?("Are you sure you want to shut down EC2 instance #{instance_id}?")
|
20
25
|
puts "Shutting down EC2 instance #{instance_id}..."
|
21
|
-
|
22
|
-
|
23
|
-
server.wait_for { state == "stopped" }
|
26
|
+
slushy = Slushy::Instance.new(fog_connection, instance_id)
|
27
|
+
slushy.stop
|
24
28
|
puts "Done!"
|
25
29
|
end
|
26
30
|
|
27
31
|
def self.destroy_ec2
|
28
|
-
return unless ENV["FORCE"] == "true" || Thor::Shell::Basic.new.yes?("Are you sure you want to destroy EC2 instance #{instance_id}?")
|
32
|
+
return unless (ENV["FORCE"] == "true") || Thor::Shell::Basic.new.yes?("Are you sure you want to destroy EC2 instance #{instance_id}?")
|
29
33
|
puts "Destroying EC2 instance #{instance_id}..."
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
File.delete('config/ec2_instance.txt')
|
34
|
+
slushy = Slushy::Instance.new(fog_connection, instance_id)
|
35
|
+
slushy.terminate
|
36
|
+
puts "Removing #{CONFIG_FILE}..."
|
37
|
+
File.delete(CONFIG_FILE)
|
35
38
|
puts "Done!"
|
36
39
|
end
|
37
40
|
|
38
41
|
def self.current_dns
|
39
|
-
|
40
|
-
|
42
|
+
puts current_server.reload.dns_name
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.current_server
|
46
|
+
fog_connection.servers.get(instance_id)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.private_key
|
50
|
+
config['server']['private_key']
|
41
51
|
end
|
42
52
|
|
43
53
|
private
|
44
54
|
|
45
55
|
def self.instance_id
|
46
|
-
@instance_id ||= File.read(
|
56
|
+
@instance_id ||= File.read(CONFIG_FILE).chomp
|
47
57
|
end
|
48
58
|
|
49
59
|
def self.config
|
@@ -56,97 +66,14 @@ module RelevanceRails
|
|
56
66
|
|
57
67
|
def self.provision_ec2_instances(name)
|
58
68
|
puts "Provisioning an instance..."
|
59
|
-
|
60
|
-
|
61
|
-
:value => "#{name}",
|
62
|
-
:resource_id => server.id)
|
63
|
-
server.private_key = config['server']['private_key']
|
64
|
-
|
65
|
-
File.open("config/ec2_instance.txt", "w") do |f|
|
66
|
-
f.puts(server.id)
|
67
|
-
end
|
69
|
+
conf = config['server']['creation_config']
|
70
|
+
conf['tags'] = {'Name' => name}
|
68
71
|
|
72
|
+
slushy = Slushy::Instance.launch(fog_connection, conf)
|
73
|
+
slushy.server.private_key = private_key
|
74
|
+
File.open(CONFIG_FILE, "w") { |f| f.puts(slushy.server.id) }
|
69
75
|
puts "Provisioned!"
|
70
|
-
|
76
|
+
slushy
|
71
77
|
end
|
72
|
-
|
73
|
-
def self.run_commands(server)
|
74
|
-
apt_installs(server)
|
75
|
-
puts "Installing chef..."
|
76
|
-
run_command(server, 'sudo gem install chef --no-ri --no-rdoc --version 0.10.8')
|
77
|
-
puts "Copying chef resources from provision directory..."
|
78
|
-
server.scp("#{Rails.root.join('provision')}/", '/tmp/chef-solo', :recursive => true)
|
79
|
-
puts "Converging server, this may take a while (10-20 minutes)"
|
80
|
-
run_command(server, 'cd /tmp/chef-solo && sudo /var/lib/gems/1.8/bin/chef-solo -c solo.rb -j dna.json')
|
81
|
-
|
82
|
-
puts "Server Instance: #{server.id}"
|
83
|
-
puts "Server IP: #{server.public_ip_address}"
|
84
|
-
server
|
85
|
-
end
|
86
|
-
|
87
|
-
def self.retry_block(times, errors, failure)
|
88
|
-
succeeded = false
|
89
|
-
attempts = 0
|
90
|
-
last_error = nil
|
91
|
-
until succeeded || attempts > times-1
|
92
|
-
begin
|
93
|
-
retval = yield
|
94
|
-
succeeded = true
|
95
|
-
rescue *errors => e
|
96
|
-
puts failure
|
97
|
-
attempts +=1
|
98
|
-
last_error = e
|
99
|
-
end
|
100
|
-
end
|
101
|
-
if succeeded
|
102
|
-
return retval
|
103
|
-
else
|
104
|
-
exit 1
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def self.apt_installs(server)
|
109
|
-
retry_block(3, [AptInstallError], "Apt-cache came from corrupt mirror, retrying update...") do
|
110
|
-
puts "Updating apt cache..."
|
111
|
-
run_apt_command(server, 'sudo apt-get update')
|
112
|
-
puts "Installing ruby..."
|
113
|
-
run_apt_command(server, 'sudo apt-get -y install ruby')
|
114
|
-
puts "Installing rubygems..."
|
115
|
-
run_apt_command(server, 'sudo apt-get -y install rubygems1.8')
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
def self.run_apt_command(server, command)
|
120
|
-
jobs = server.ssh(command)
|
121
|
-
raise AptInstallError unless jobs_succeeded?(jobs)
|
122
|
-
end
|
123
|
-
|
124
|
-
def self.run_command(server, command)
|
125
|
-
jobs = server.ssh(command)
|
126
|
-
exit 1 unless jobs_succeeded?(jobs)
|
127
|
-
end
|
128
|
-
|
129
|
-
def self.wait_for_ssh(server)
|
130
|
-
puts "Waiting for ssh connectivity..."
|
131
|
-
server.wait_for { ready? }
|
132
|
-
retry_block(5, [Errno::ECONNREFUSED, Timeout::Error], "Connecting to Amazon refused. Retrying...") do
|
133
|
-
sleep 10
|
134
|
-
Timeout.timeout(60) { server.ssh('ls') }
|
135
|
-
end
|
136
|
-
puts "Server up and listening for SSH!"
|
137
|
-
end
|
138
|
-
|
139
|
-
def self.jobs_succeeded?(jobs)
|
140
|
-
return true if jobs.all? { |job| job.status == 0 }
|
141
|
-
jobs.each do |job|
|
142
|
-
puts "----------------------"
|
143
|
-
puts "Command '#{job.command}'"
|
144
|
-
puts "STDOUT: #{job.stdout}"
|
145
|
-
puts "STDERR: #{job.stderr}"
|
146
|
-
puts "----------------------"
|
147
|
-
end
|
148
|
-
false
|
149
|
-
end
|
150
|
-
|
151
78
|
end
|
152
79
|
end
|
@@ -3,8 +3,8 @@ require 'tmpdir'
|
|
3
3
|
module RelevanceRails::PublicKeyFetcher
|
4
4
|
def self.public_keys
|
5
5
|
pubkeys = []
|
6
|
-
return pubkeys unless File.exist?
|
7
|
-
git_url = File.read
|
6
|
+
return pubkeys unless File.exist?(user_git_url)
|
7
|
+
git_url = File.read(user_git_url)
|
8
8
|
return pubkeys unless git_url =~ /\/(.*)\.git/
|
9
9
|
repo_name = $1
|
10
10
|
Dir.mktmpdir('public_keys') { |dir|
|
@@ -3,17 +3,17 @@ require 'relevance_rails'
|
|
3
3
|
module RelevanceRails
|
4
4
|
class Runner
|
5
5
|
def self.start(argv=ARGV)
|
6
|
-
if argv.empty? || argv[0] == '--help' || argv[0] == '-h'
|
6
|
+
if argv.empty? || (argv[0] == '--help') || (argv[0] == '-h')
|
7
7
|
print_help
|
8
|
-
elsif argv.delete
|
8
|
+
elsif argv.delete('--version')
|
9
9
|
puts "RelevanceRails #{RelevanceRails::VERSION}"
|
10
10
|
elsif argv[0] == 'new'
|
11
11
|
add_default_options! argv
|
12
|
-
if ENV['rvm_path'].nil?
|
12
|
+
if ENV['rvm_path'].nil? || ENV['NO_RVM']
|
13
13
|
exec 'rails', *argv
|
14
14
|
else
|
15
15
|
app_name = argv[1]
|
16
|
-
env = setup_rvm
|
16
|
+
env = setup_rvm(app_name)
|
17
17
|
|
18
18
|
new_rvm_string = "#{env.environment_name.split('@')[0]}@#{app_name}"
|
19
19
|
install_relevance_rails argv, new_rvm_string, env.environment_name
|
@@ -54,9 +54,7 @@ STR
|
|
54
54
|
# in 1.12.0, so you don't use this trick anymore.
|
55
55
|
$LOAD_PATH.unshift "#{ENV['rvm_path']}/lib"
|
56
56
|
end
|
57
|
-
|
58
57
|
require 'rvm'
|
59
|
-
|
60
58
|
env = RVM::Environment.current
|
61
59
|
env.gemset_create(app_name)
|
62
60
|
env
|
@@ -66,13 +64,19 @@ STR
|
|
66
64
|
child_env = RVM::Environment.new(new_rvm_string)
|
67
65
|
puts "Installing relevance_rails into the app's gemset..."
|
68
66
|
|
69
|
-
result = if argv.delete
|
70
|
-
|
71
|
-
|
67
|
+
result = if argv.delete('--relevance-dev')
|
68
|
+
gem_dir = "#{ENV['rvm_path']}/gems/#{current_gemset}/cache"
|
69
|
+
require 'elzar'
|
70
|
+
child_env.run('gem', 'install', "#{gem_dir}/elzar-#{Elzar::VERSION}.gem")
|
71
|
+
child_env.run('gem', 'install', "#{gem_dir}/relevance_rails-#{RelevanceRails::VERSION}.gem")
|
72
72
|
else
|
73
73
|
child_env.run('gem', 'install', 'relevance_rails', '-v', RelevanceRails::VERSION)
|
74
74
|
end
|
75
|
-
|
75
|
+
if result.exit_status != 0
|
76
|
+
abort "Unable to install relevance_rails into the new gemset. " +
|
77
|
+
"\nExit code: #{result.exit_status}" +
|
78
|
+
"\nFailed with:\n#{result.stderr}"
|
79
|
+
end
|
76
80
|
end
|
77
81
|
|
78
82
|
def self.add_default_options!(argv)
|
data/lib/relevance_rails.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require "relevance_rails/version"
|
2
2
|
require "relevance_rails/public_key_fetcher"
|
3
|
-
require
|
4
|
-
require 'relevance_rails/railtie' if defined? Rails
|
3
|
+
require 'relevance_rails/railtie' if defined?(Rails)
|
5
4
|
require 'relevance_rails/generator_overrides'
|
6
5
|
|
7
6
|
module RelevanceRails
|
data/relevance_rails.gemspec
CHANGED
@@ -8,31 +8,28 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.homepage = "http://github.com/relevance/relevance_rails"
|
9
9
|
s.authors = ["Alex Redington"]
|
10
10
|
s.email = ["alex.redington@thinkrelevance.com"]
|
11
|
-
s.homepage = ""
|
12
11
|
s.summary = %q{Rails 3 Relevance style, with all infrastructure bits automated away.}
|
13
12
|
s.description = %q{A Rails 3 wrapper which forces template use and includes a plethora of generators for standard Relevance bits.}
|
14
13
|
|
15
|
-
s.rubyforge_project = "relevance_rails"
|
16
|
-
|
17
14
|
s.files = `git ls-files`.split("\n")
|
18
15
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
16
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
-
s.require_paths = ["lib"]
|
21
17
|
|
22
|
-
s.bindir = 'bin'
|
23
18
|
s.executables = ['relevance_rails']
|
24
19
|
|
25
|
-
# specify any dependencies here; for example:
|
26
|
-
s.add_runtime_dependency 'rails', '~> 3.2'
|
27
|
-
|
28
20
|
# be aware that we're monkey-patching fog in fog_ext/ssh.rb;
|
29
21
|
# if we update fog, that monkey-patch might need to be
|
30
22
|
# revisited
|
31
23
|
s.add_runtime_dependency 'fog', '1.3.1'
|
32
|
-
|
24
|
+
s.add_runtime_dependency 'rails', '~> 3.2'
|
25
|
+
s.add_runtime_dependency 'slushy', '~> 0.1.1'
|
33
26
|
s.add_runtime_dependency 'thor', '~> 0.14.6'
|
34
|
-
s.
|
27
|
+
s.add_runtime_dependency 'elzar', '~> 0.1.0'
|
28
|
+
|
35
29
|
s.add_development_dependency 'capybara'
|
36
|
-
s.add_development_dependency '
|
30
|
+
s.add_development_dependency 'fakefs'
|
31
|
+
s.add_development_dependency 'guard-rspec'
|
32
|
+
s.add_development_dependency 'pry'
|
37
33
|
s.add_development_dependency 'rake', '~> 0.9.2.2'
|
34
|
+
s.add_development_dependency 'rspec'
|
38
35
|
end
|
data/script/ci
CHANGED
@@ -25,9 +25,13 @@ function files_must_NOT_exist {
|
|
25
25
|
RAILS_APP="app_for_ci"
|
26
26
|
TARGET_HOST="placeholder.example.com"
|
27
27
|
|
28
|
+
# Set overrideable defaults
|
29
|
+
: ${CI_DATABASE:="postgresql"}
|
30
|
+
: ${CI_RUBY_VERSION:="ruby-1.9.2"}
|
31
|
+
|
28
32
|
# Setup RVM
|
29
33
|
source "$HOME/.rvm/scripts/rvm"
|
30
|
-
rvm use "
|
34
|
+
rvm use "$CI_RUBY_VERSION@relevance_rails"
|
31
35
|
echo "RVM is now using:` rvm current`"
|
32
36
|
|
33
37
|
# exit if any statement fails;
|
@@ -50,7 +54,7 @@ rvm --force gemset delete $RAILS_APP
|
|
50
54
|
set -e
|
51
55
|
echo "Done"
|
52
56
|
|
53
|
-
relevance_rails new $RAILS_APP --database
|
57
|
+
relevance_rails new $RAILS_APP --database=$CI_DATABASE --relevance-dev
|
54
58
|
|
55
59
|
# NOTE: this does NOT change the RVM gemset; we set it manually below
|
56
60
|
builtin cd $RAILS_APP
|
data/script/ci_nightly
CHANGED
@@ -13,36 +13,53 @@ function stop_server_and_exit {
|
|
13
13
|
echo "Stopping newly-created server..."
|
14
14
|
bundle exec rake provision:stop FORCE=true --trace
|
15
15
|
echo "Done."
|
16
|
+
else
|
17
|
+
echo "No server to stop (i.e. can't find config/ec2_instance.txt)."
|
16
18
|
fi
|
17
19
|
|
18
20
|
echo "BUILD FAILED"
|
19
21
|
exit 1
|
20
22
|
}
|
21
23
|
|
24
|
+
function cd_rails_app {
|
25
|
+
builtin cd $RAILS_APP
|
26
|
+
rvm gemset use $RAILS_APP
|
27
|
+
}
|
28
|
+
|
22
29
|
echo "RVM is now using:` rvm current`"
|
23
30
|
|
31
|
+
if [ -z $CI_RUBY_VERSION ]; then
|
32
|
+
echo 'You must specify $CI_RUBY_VERSION!'
|
33
|
+
exit 1
|
34
|
+
fi
|
35
|
+
|
36
|
+
if [ -z $CI_DATABASE ]; then
|
37
|
+
echo 'You must specify $CI_DATABASE!'
|
38
|
+
exit 1
|
39
|
+
fi
|
40
|
+
|
24
41
|
set -e
|
25
42
|
./script/ci
|
26
43
|
set +e
|
27
44
|
|
28
45
|
source "$HOME/.rvm/scripts/rvm"
|
29
|
-
rvm use "
|
46
|
+
rvm use "$CI_RUBY_VERSION@$RAILS_APP"
|
30
47
|
echo "RVM is now using:` rvm current`"
|
31
48
|
|
32
49
|
builtin cd $RAILS_APP
|
33
|
-
|
50
|
+
|
34
51
|
echo "Provisioning an EC2 instance..."
|
35
52
|
rm -f $EC2_MEMENTO_FILE
|
36
53
|
server_name="Nightly Build Testing - `date "+%Y-%m-%d %H:%M:%S"` "
|
37
54
|
bundle exec rake --trace provision:ec2 NAME="$server_name"
|
38
55
|
[ $? -ne 0 ] && stop_server_and_exit
|
39
56
|
echo "Done!"
|
40
|
-
|
57
|
+
|
41
58
|
echo "Determine the EC2 instance's DNS name..."
|
42
59
|
TARGET_HOST=`bundle exec rake provision:current_dns`
|
43
60
|
[ $? -ne 0 ] && stop_server_and_exit
|
44
61
|
echo "Done."
|
45
|
-
|
62
|
+
|
46
63
|
echo "Generating relevance_rails deployment scripts..."
|
47
64
|
./script/rails generate deployment staging $TARGET_HOST --force
|
48
65
|
[ $? -ne 0 ] && stop_server_and_exit
|
@@ -67,11 +84,10 @@ echo "RVM is now using:` rvm current`"
|
|
67
84
|
|
68
85
|
echo "Running the acceptance tests against our newly-created server..."
|
69
86
|
ACCEPTANCE_HOST=$TARGET_HOST rake acceptance --trace
|
70
|
-
[ $? -ne 0 ] && stop_server_and_exit
|
87
|
+
[ $? -ne 0 ] && cd_rails_app && stop_server_and_exit
|
71
88
|
echo "Done."
|
72
89
|
|
73
|
-
|
74
|
-
rvm gemset use $RAILS_APP
|
90
|
+
cd_rails_app
|
75
91
|
|
76
92
|
echo "Terminating our newly-created server..."
|
77
93
|
bundle exec rake provision:destroy FORCE=true --trace
|
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
RAILS_APP="elzar_nightly_app"
|
4
|
+
EC2_MEMENTO_FILE="config/ec2_instance.txt"
|
5
|
+
|
6
|
+
function stop_server_and_exit {
|
7
|
+
if [ -f $EC2_MEMENTO_FILE ]; then
|
8
|
+
echo "Stopping newly-created server..."
|
9
|
+
bundle exec rake provision:stop FORCE=true --trace
|
10
|
+
else
|
11
|
+
echo "No server to stop (i.e. can't find config/ec2_instance.txt)."
|
12
|
+
fi
|
13
|
+
|
14
|
+
echo "BUILD FAILED"
|
15
|
+
exit 1
|
16
|
+
}
|
17
|
+
|
18
|
+
source "$HOME/.rvm/scripts/rvm"
|
19
|
+
export CI_GEMSET=elzar_nightly
|
20
|
+
# Tests and app are all running in CI_GEMSET
|
21
|
+
export NO_RVM=true
|
22
|
+
|
23
|
+
rvm use "$CI_RUBY_VERSION@$CI_GEMSET"
|
24
|
+
gem install bundler
|
25
|
+
bundle install
|
26
|
+
|
27
|
+
# DO NOT bundle exec rake - fakefs activation borks everything
|
28
|
+
rake elzar_nightly
|
29
|
+
|
30
|
+
[ $? -ne 0 ] && builtin cd $RAILS_APP && stop_server_and_exit
|
31
|
+
|
32
|
+
builtin cd $RAILS_APP
|
33
|
+
bundle exec rake provision:destroy FORCE=true --trace
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'relevance_rails/provision'
|
4
|
+
|
5
|
+
describe "Elzar recipes", :ci => true do
|
6
|
+
let(:rails_app) { ENV['RAILS_APP'] || 'elzar_nightly_app' }
|
7
|
+
let(:server_name) { "Elzar Nightly (#{database} / #{ruby_version}) - #{Time.now.strftime("%Y-%m-%d %H:%M:%S")}" }
|
8
|
+
let(:database) { ENV['CI_DATABASE'] || 'mysql' }
|
9
|
+
let(:database_cmd) { { 'mysql' => 'mysql', 'postgresql' => 'psql'}[database] }
|
10
|
+
let(:ruby_version) { ENV['CI_RUBY_VERSION'] || 'ruby-1.9.3-p125' }
|
11
|
+
let(:ruby_bin_path) {
|
12
|
+
ruby_version.start_with?('ree-') ? '/opt/ruby-enterprise/bin' : '/opt/relevance-ruby/bin'
|
13
|
+
}
|
14
|
+
let(:gemset) { ENV['CI_GEMSET'] || 'elzar_nightly' }
|
15
|
+
|
16
|
+
# wrapper around system
|
17
|
+
def shell(cmd)
|
18
|
+
puts "Executing #{cmd}..."
|
19
|
+
system(cmd)
|
20
|
+
abort "Command '#{cmd}' failed" unless $?.success?
|
21
|
+
end
|
22
|
+
|
23
|
+
def sh(cmd)
|
24
|
+
shell "#{ruby_version}@#{gemset} -S #{cmd}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def rake(cmd)
|
28
|
+
sh "bundle exec rake #{cmd}"
|
29
|
+
end
|
30
|
+
|
31
|
+
# New app is created in current gemset
|
32
|
+
def create_new_app
|
33
|
+
rake 'install --trace'
|
34
|
+
FileUtils.rm_rf(rails_app)
|
35
|
+
sh "relevance_rails new #{rails_app} --database=#{database} --relevance-dev"
|
36
|
+
end
|
37
|
+
|
38
|
+
def ssh(cmd)
|
39
|
+
server = RelevanceRails::Provision.current_server
|
40
|
+
server.username = 'relevance'
|
41
|
+
server.private_key = RelevanceRails::Provision.private_key
|
42
|
+
job = nil
|
43
|
+
capture_stdout { job = server.ssh(cmd).first }
|
44
|
+
job
|
45
|
+
end
|
46
|
+
|
47
|
+
def command_succeeds(cmd)
|
48
|
+
ssh(cmd).status.should == 0
|
49
|
+
end
|
50
|
+
|
51
|
+
before(:all) do
|
52
|
+
create_new_app
|
53
|
+
Dir.chdir rails_app
|
54
|
+
rake %[provision:ec2 NAME="#{server_name}" --trace]
|
55
|
+
end
|
56
|
+
|
57
|
+
it "installs the right ruby" do
|
58
|
+
job = ssh "#{ruby_bin_path}/ruby -v"
|
59
|
+
if ruby_version.start_with?('ree-')
|
60
|
+
job.stdout.include?("Ruby Enterprise Edition").should be_true
|
61
|
+
else
|
62
|
+
version_number = ruby_version.sub(/^ruby/, '').tr('-', '')
|
63
|
+
job.stdout.start_with?("ruby #{version_number}").should be_true
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
it "installs the correct database" do
|
68
|
+
command_succeeds("#{database_cmd} --version")
|
69
|
+
end
|
70
|
+
|
71
|
+
it "creates a deploy user" do
|
72
|
+
command_succeeds("ls /home/deploy")
|
73
|
+
end
|
74
|
+
|
75
|
+
it "creates nginx and configures it" do
|
76
|
+
# TODO: get nginx version from elzar
|
77
|
+
command_succeeds "/opt/nginx-1.0.10/sbin/nginx -h"
|
78
|
+
command_succeeds "ls /etc/nginx/nginx.conf"
|
79
|
+
command_succeeds "ls /etc/init.d/nginx"
|
80
|
+
command_succeeds "ls /etc/nginx/sites-enabled/#{rails_app}"
|
81
|
+
end
|
82
|
+
|
83
|
+
it "installs passenger gem and configures it" do
|
84
|
+
command_succeeds "#{ruby_bin_path}/gem list passenger$ |grep passenger -q"
|
85
|
+
command_succeeds "ls /etc/nginx/conf.d/passenger.conf"
|
86
|
+
command_succeeds %[grep -q "passenger_ruby #{ruby_bin_path}/ruby;" /etc/nginx/conf.d/passenger.conf]
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'fakefs/spec_helpers'
|
4
|
+
require 'generators/provision_config/provision_config_generator'
|
5
|
+
|
6
|
+
describe ProvisionConfigGenerator do
|
7
|
+
subject { ProvisionConfigGenerator.new(["name"]) }
|
8
|
+
|
9
|
+
describe "#local_keys" do
|
10
|
+
include FakeFS::SpecHelpers
|
11
|
+
|
12
|
+
def write_fixture(path, contents)
|
13
|
+
FileUtils.mkdir_p(File.dirname(path))
|
14
|
+
File.open(path, "w") { |f| f.write(contents) }
|
15
|
+
end
|
16
|
+
|
17
|
+
it "returns the contents of id_rsa.pub when it exists" do
|
18
|
+
write_fixture(File.expand_path("~/.ssh/id_rsa.pub"), "RSA-public-key")
|
19
|
+
subject.send(:local_keys).should == ["RSA-public-key"]
|
20
|
+
end
|
21
|
+
|
22
|
+
it "returns the contents of id_dsa.pub when it exists" do
|
23
|
+
write_fixture(File.expand_path("~/.ssh/id_dsa.pub"), "DSA-public-key")
|
24
|
+
subject.send(:local_keys).should == ["DSA-public-key"]
|
25
|
+
end
|
26
|
+
|
27
|
+
it "returns the contents of id_ecdsa.pub when it exists" do
|
28
|
+
write_fixture(File.expand_path("~/.ssh/id_ecdsa.pub"), "ECDSA-public-key")
|
29
|
+
subject.send(:local_keys).should == ["ECDSA-public-key"]
|
30
|
+
end
|
31
|
+
|
32
|
+
it "returns the contents of id_dsa.pub when both id_dsa.pub and id_rsa.pub exist" do
|
33
|
+
write_fixture(File.expand_path("~/.ssh/id_dsa.pub"), "DSA-public-key")
|
34
|
+
write_fixture(File.expand_path("~/.ssh/id_rsa.pub"), "RSA-public-key")
|
35
|
+
subject.send(:local_keys).should == ["DSA-public-key"]
|
36
|
+
end
|
37
|
+
|
38
|
+
it "ignores trailing newlines" do
|
39
|
+
write_fixture(File.expand_path("~/.ssh/id_rsa.pub"), "RSA-public-key\n\n")
|
40
|
+
subject.send(:local_keys).should == ["RSA-public-key"]
|
41
|
+
end
|
42
|
+
|
43
|
+
it "ignores blank lines" do
|
44
|
+
write_fixture(File.expand_path("~/.ssh/id_rsa.pub"), "\n\nRSA-public-key\n\n\n")
|
45
|
+
subject.send(:local_keys).should == ["RSA-public-key"]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "#ssh_agent_keys" do
|
50
|
+
it "retrieves keys from ssh agent" do
|
51
|
+
subject.should_receive("`").with("ssh-add -L") do
|
52
|
+
system("true")
|
53
|
+
"my-public-key\nanother-public-key"
|
54
|
+
end
|
55
|
+
subject.send(:ssh_agent_keys).should == ["my-public-key", "another-public-key"]
|
56
|
+
end
|
57
|
+
|
58
|
+
it "ignores output from ssh-add when execution fails" do
|
59
|
+
subject.stub("`") do
|
60
|
+
system("false")
|
61
|
+
# Actual message that comes back from failed call
|
62
|
+
"The agent has no entities"
|
63
|
+
end
|
64
|
+
subject.send(:ssh_agent_keys).should == []
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "#fetch_keys" do
|
69
|
+
it "returns local keys when they exist" do
|
70
|
+
subject.stub(:local_keys).and_return(["key-from-local-file"])
|
71
|
+
subject.stub(:ssh_agent_keys).and_return(["key-from-ssh-agent"])
|
72
|
+
RelevanceRails::PublicKeyFetcher.stub(:public_keys).and_return([])
|
73
|
+
subject.send(:fetch_keys).should == ["key-from-local-file"]
|
74
|
+
end
|
75
|
+
|
76
|
+
it "returns keys from ssh agent when local keys do NOT exist" do
|
77
|
+
subject.stub(:local_keys).and_return([])
|
78
|
+
subject.stub(:ssh_agent_keys).and_return(["key-from-ssh-agent"])
|
79
|
+
RelevanceRails::PublicKeyFetcher.stub(:public_keys).and_return([])
|
80
|
+
subject.send(:fetch_keys).should == ["key-from-ssh-agent"]
|
81
|
+
end
|
82
|
+
|
83
|
+
it "combines local keys with those from PublicKeyFetcher" do
|
84
|
+
subject.stub(:local_keys).and_return(["key-from-local-file"])
|
85
|
+
RelevanceRails::PublicKeyFetcher.stub(:public_keys).and_return(["key-from-git-repo"])
|
86
|
+
subject.send(:fetch_keys).should == ["key-from-local-file", "key-from-git-repo"]
|
87
|
+
end
|
88
|
+
|
89
|
+
it "combines ssh agent keys with those from PublicKeyFetcher" do
|
90
|
+
subject.stub(:local_keys).and_return([])
|
91
|
+
subject.stub(:ssh_agent_keys).and_return(["key-from-ssh-agent"])
|
92
|
+
RelevanceRails::PublicKeyFetcher.stub(:public_keys).and_return(["key-from-git-repo"])
|
93
|
+
subject.send(:fetch_keys).should == ["key-from-ssh-agent", "key-from-git-repo"]
|
94
|
+
end
|
95
|
+
|
96
|
+
it "excludes duplicate keys" do
|
97
|
+
subject.stub(:local_keys).and_return(["key-1", "key-2", "key-1"])
|
98
|
+
RelevanceRails::PublicKeyFetcher.stub(:public_keys).and_return(["key-3", "key-2", "key-3"])
|
99
|
+
subject.send(:fetch_keys).should == ["key-1", "key-2", "key-3"]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "#check_authorized_keys" do
|
104
|
+
it "aborts if no ssh-keys are found" do
|
105
|
+
subject.stub(:fetch_keys).and_return([])
|
106
|
+
should_abort_with(/^No SSH public keys were found!/) do
|
107
|
+
subject.check_authorized_keys
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
it "doesn't abort if ssh-keys are found" do
|
112
|
+
subject.should_receive(:fetch_keys).and_return(['ssh-rsa ZZZZ'])
|
113
|
+
expect { subject.check_authorized_keys }.to_not raise_error
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -15,10 +15,9 @@ describe RelevanceRails::Runner do
|
|
15
15
|
it "new calls exec" do
|
16
16
|
RelevanceRails::Runner.should_receive(:exec).with(anything,
|
17
17
|
'-S', 'rails', 'new', 'the_app', '-m',
|
18
|
-
File.expand_path(File.dirname(__FILE__)
|
19
|
-
"/../../lib/relevance_rails/relevance_rails_template.rb"))
|
18
|
+
File.expand_path("../../../lib/relevance_rails/relevance_rails_template.rb", File.dirname(__FILE__)))
|
20
19
|
RelevanceRails::Runner.should_receive(:install_relevance_rails)
|
21
|
-
env = mock
|
20
|
+
env = mock(:environment_name => '1.9.3@default')
|
22
21
|
RelevanceRails::Runner.should_receive(:setup_rvm).and_return(env)
|
23
22
|
start('new', 'the_app')
|
24
23
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -44,6 +44,7 @@ RSpec.configure do |config|
|
|
44
44
|
config.include TestHelpers
|
45
45
|
config.filter_run :focused => true
|
46
46
|
config.filter_run_excluding :acceptance => true
|
47
|
+
config.filter_run_excluding :ci => true
|
47
48
|
config.filter_run_excluding :disabled => true
|
48
49
|
config.run_all_when_everything_filtered = true
|
49
50
|
end
|
data/techdebt.md
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
* TECHDEBT BY COMPONENT *
|
2
2
|
|
3
3
|
* GENERAL
|
4
|
-
** remove heredocs, replace by erb templates
|
5
4
|
** move all general configuration to a ~/.relevance_rails.yml file (AWS stuff, keys git repo stuff)
|
6
|
-
** cleaner rvm version detection - intermittenly picks up no version
|
7
5
|
** intermittent mysql::server failures (mysql server not up yet) on `vagrant up`. Attempt fix in site_cookbooks
|
8
|
-
** intermittent setup failure - apt-get update fails with 404s or ruby not found
|
9
6
|
** when generating an app with --database=postgresql, provision_config
|
10
7
|
generator intermittently fails at the beginning with different gem not found
|
11
8
|
errors. Generating the app more than once or inspecting the problem solves it
|
12
9
|
** provision_config generator intermittently can't detect current working directory which breaks
|
13
10
|
git commands. Current solution of sprinkling Dir.chdir is a bandaid at best.
|
14
|
-
|
15
|
-
* Provisioning an instance
|
16
|
-
** Don't hardcode path to chef binstub, caused by ubuntu installing weirdness
|
17
11
|
** Make the deployment generator idempotent
|
18
|
-
**
|
19
|
-
|
20
|
-
|
12
|
+
** Have pg and mysql recipes depend on a unified gem install method. This method would call
|
13
|
+
gem_package for mri and ree_gem for ree. When this is done, we can add --dont-install-useful-gems
|
14
|
+
back to the ree installer.
|
15
|
+
** Upgrade to haml > 3.1.5 once AbstractController::Rendering#render_to_body bug is resolved
|
16
|
+
** bundle exec rake elzar_nightly breaks due to fakefs being activated early in require chain.
|
17
|
+
Calling the rake task works fine locally and on CI. Attempting to not require fakefs in the
|
18
|
+
Gemfile didn't work.
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: relevance_rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,8 +9,24 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-05-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: fog
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - '='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.3.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - '='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.3.1
|
14
30
|
- !ruby/object:Gem::Dependency
|
15
31
|
name: rails
|
16
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -28,21 +44,21 @@ dependencies:
|
|
28
44
|
- !ruby/object:Gem::Version
|
29
45
|
version: '3.2'
|
30
46
|
- !ruby/object:Gem::Dependency
|
31
|
-
name:
|
47
|
+
name: slushy
|
32
48
|
requirement: !ruby/object:Gem::Requirement
|
33
49
|
none: false
|
34
50
|
requirements:
|
35
|
-
- -
|
51
|
+
- - ~>
|
36
52
|
- !ruby/object:Gem::Version
|
37
|
-
version: 1.
|
53
|
+
version: 0.1.1
|
38
54
|
type: :runtime
|
39
55
|
prerelease: false
|
40
56
|
version_requirements: !ruby/object:Gem::Requirement
|
41
57
|
none: false
|
42
58
|
requirements:
|
43
|
-
- -
|
59
|
+
- - ~>
|
44
60
|
- !ruby/object:Gem::Version
|
45
|
-
version: 1.
|
61
|
+
version: 0.1.1
|
46
62
|
- !ruby/object:Gem::Dependency
|
47
63
|
name: thor
|
48
64
|
requirement: !ruby/object:Gem::Requirement
|
@@ -60,7 +76,23 @@ dependencies:
|
|
60
76
|
- !ruby/object:Gem::Version
|
61
77
|
version: 0.14.6
|
62
78
|
- !ruby/object:Gem::Dependency
|
63
|
-
name:
|
79
|
+
name: elzar
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 0.1.0
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 0.1.0
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: capybara
|
64
96
|
requirement: !ruby/object:Gem::Requirement
|
65
97
|
none: false
|
66
98
|
requirements:
|
@@ -76,7 +108,7 @@ dependencies:
|
|
76
108
|
- !ruby/object:Gem::Version
|
77
109
|
version: '0'
|
78
110
|
- !ruby/object:Gem::Dependency
|
79
|
-
name:
|
111
|
+
name: fakefs
|
80
112
|
requirement: !ruby/object:Gem::Requirement
|
81
113
|
none: false
|
82
114
|
requirements:
|
@@ -92,7 +124,23 @@ dependencies:
|
|
92
124
|
- !ruby/object:Gem::Version
|
93
125
|
version: '0'
|
94
126
|
- !ruby/object:Gem::Dependency
|
95
|
-
name: rspec
|
127
|
+
name: guard-rspec
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
- !ruby/object:Gem::Dependency
|
143
|
+
name: pry
|
96
144
|
requirement: !ruby/object:Gem::Requirement
|
97
145
|
none: false
|
98
146
|
requirements:
|
@@ -123,6 +171,22 @@ dependencies:
|
|
123
171
|
- - ~>
|
124
172
|
- !ruby/object:Gem::Version
|
125
173
|
version: 0.9.2.2
|
174
|
+
- !ruby/object:Gem::Dependency
|
175
|
+
name: rspec
|
176
|
+
requirement: !ruby/object:Gem::Requirement
|
177
|
+
none: false
|
178
|
+
requirements:
|
179
|
+
- - ! '>='
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '0'
|
182
|
+
type: :development
|
183
|
+
prerelease: false
|
184
|
+
version_requirements: !ruby/object:Gem::Requirement
|
185
|
+
none: false
|
186
|
+
requirements:
|
187
|
+
- - ! '>='
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: '0'
|
126
190
|
description: A Rails 3 wrapper which forces template use and includes a plethora of
|
127
191
|
generators for standard Relevance bits.
|
128
192
|
email:
|
@@ -137,6 +201,7 @@ files:
|
|
137
201
|
- .travis.yml
|
138
202
|
- CHANGELOG.md
|
139
203
|
- Gemfile
|
204
|
+
- Guardfile
|
140
205
|
- README.md
|
141
206
|
- Rakefile
|
142
207
|
- USAGE.md
|
@@ -146,7 +211,6 @@ files:
|
|
146
211
|
- lib/generators/fixtures/fixtures_generator.rb
|
147
212
|
- lib/generators/provision_config/provision_config_generator.rb
|
148
213
|
- lib/generators/provision_config/templates/Capfile
|
149
|
-
- lib/generators/provision_config/templates/authorized_keys.json.erb
|
150
214
|
- lib/generators/provision_config/templates/deploy.rb.erb
|
151
215
|
- lib/generators/provision_config/templates/recipes_deploy.rb
|
152
216
|
- lib/generators/provision_config/templates/vagrant.rb
|
@@ -158,7 +222,6 @@ files:
|
|
158
222
|
- lib/generators/relevance_file/templates/database.example.yml.postgresql.erb
|
159
223
|
- lib/generators/relevance_file/templates/spec_helper.rb
|
160
224
|
- lib/relevance_rails.rb
|
161
|
-
- lib/relevance_rails/chef_dna.rb
|
162
225
|
- lib/relevance_rails/fog_ext/ssh.rb
|
163
226
|
- lib/relevance_rails/generator_overrides.rb
|
164
227
|
- lib/relevance_rails/provision.rb
|
@@ -171,13 +234,14 @@ files:
|
|
171
234
|
- relevance_rails.gemspec
|
172
235
|
- script/ci
|
173
236
|
- script/ci_nightly
|
237
|
+
- script/elzar_nightly
|
174
238
|
- spec/acceptance_spec.rb
|
175
|
-
- spec/
|
176
|
-
- spec/lib/
|
177
|
-
- spec/lib/runner_spec.rb
|
239
|
+
- spec/elzar_recipes_spec.rb
|
240
|
+
- spec/lib/generators/provision_config/provision_config_generator_spec.rb
|
241
|
+
- spec/lib/relevance_rails/runner_spec.rb
|
178
242
|
- spec/spec_helper.rb
|
179
243
|
- techdebt.md
|
180
|
-
homepage:
|
244
|
+
homepage: http://github.com/relevance/relevance_rails
|
181
245
|
licenses: []
|
182
246
|
post_install_message:
|
183
247
|
rdoc_options: []
|
@@ -189,16 +253,27 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
189
253
|
- - ! '>='
|
190
254
|
- !ruby/object:Gem::Version
|
191
255
|
version: '0'
|
256
|
+
segments:
|
257
|
+
- 0
|
258
|
+
hash: 3573380774667230504
|
192
259
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
193
260
|
none: false
|
194
261
|
requirements:
|
195
262
|
- - ! '>='
|
196
263
|
- !ruby/object:Gem::Version
|
197
264
|
version: '0'
|
265
|
+
segments:
|
266
|
+
- 0
|
267
|
+
hash: 3573380774667230504
|
198
268
|
requirements: []
|
199
|
-
rubyforge_project:
|
200
|
-
rubygems_version: 1.8.
|
269
|
+
rubyforge_project:
|
270
|
+
rubygems_version: 1.8.24
|
201
271
|
signing_key:
|
202
272
|
specification_version: 3
|
203
273
|
summary: Rails 3 Relevance style, with all infrastructure bits automated away.
|
204
|
-
test_files:
|
274
|
+
test_files:
|
275
|
+
- spec/acceptance_spec.rb
|
276
|
+
- spec/elzar_recipes_spec.rb
|
277
|
+
- spec/lib/generators/provision_config/provision_config_generator_spec.rb
|
278
|
+
- spec/lib/relevance_rails/runner_spec.rb
|
279
|
+
- spec/spec_helper.rb
|
@@ -1,34 +0,0 @@
|
|
1
|
-
module RelevanceRails::ChefDNA
|
2
|
-
def self.gene_splice(json, database)
|
3
|
-
set_ruby(json)
|
4
|
-
set_database(json, database)
|
5
|
-
end
|
6
|
-
|
7
|
-
def self.set_database(json, database)
|
8
|
-
if database == 'postgresql'
|
9
|
-
db_index = json['run_list'].find_index { |e| e == 'mysql::server' || e == 'role[postgres_database]'}
|
10
|
-
json['run_list'][db_index] = 'role[postgres_database]'
|
11
|
-
elsif database.nil? || database == 'mysql'
|
12
|
-
db_index = json['run_list'].find_index { |e| e == 'mysql::server' || e == 'role[postgres_database]'}
|
13
|
-
json['run_list'][db_index] = 'mysql::server'
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.set_ruby(json)
|
18
|
-
if RelevanceRails.ruby_version =~ /^ree-(.*)/i
|
19
|
-
json['ruby_enterprise']['version'] = $1
|
20
|
-
json['ruby_enterprise']['url'] = "http://rubyenterpriseedition.googlecode.com/files/ruby-enterprise-#{$1}"
|
21
|
-
appstack_index = json['run_list'].find_index {|e| e[/^role\[.*_appstack\]$/] }
|
22
|
-
json['run_list'][appstack_index] = 'role[enterprise_appstack]'
|
23
|
-
elsif RelevanceRails.ruby_version =~ /^ruby-(.*)/i
|
24
|
-
full_version = $1
|
25
|
-
json['ruby']['version'] = full_version
|
26
|
-
major_version = full_version[/(\d\.\d).*/, 1]
|
27
|
-
json['ruby']['url'] = "http://ftp.ruby-lang.org/pub/ruby/#{major_version}/ruby-#{full_version}.tar.gz"
|
28
|
-
appstack_index = json['run_list'].find_index {|e| e[/^role\[.*_appstack\]$/] }
|
29
|
-
json['run_list'][appstack_index] = 'role[ruby_appstack]'
|
30
|
-
else
|
31
|
-
raise "Your ruby is NOT SUPPORTED. Please use ree or ruby."
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'generators/provision_config/provision_config_generator'
|
3
|
-
|
4
|
-
describe ProvisionConfigGenerator do
|
5
|
-
context '#check_authorized_keys' do
|
6
|
-
subject { ProvisionConfigGenerator.new(['name']) }
|
7
|
-
|
8
|
-
it "aborts if no ssh-keys are found" do
|
9
|
-
subject.should_receive(:`).and_return do
|
10
|
-
system('exit 1')
|
11
|
-
# Actual message that comes back from failed call
|
12
|
-
'The agent has no entities'
|
13
|
-
end
|
14
|
-
RelevanceRails::PublicKeyFetcher.should_receive(:public_keys).and_return([])
|
15
|
-
|
16
|
-
should_abort_with(/^No ssh keys were found!/) do
|
17
|
-
subject.check_authorized_keys
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
it "doesn't abort if ssh-keys are found" do
|
22
|
-
subject.should_receive(:fetch_keys).and_return(['ssh-rsa ZZZZ'])
|
23
|
-
expect { subject.check_authorized_keys }.to_not raise_error
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
data/spec/lib/provision_spec.rb
DELETED
@@ -1,68 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'relevance_rails/provision'
|
3
|
-
|
4
|
-
describe RelevanceRails::Provision do
|
5
|
-
def job(options={})
|
6
|
-
options = {:stdout => '', :stderr => '', :status => 0}.update options
|
7
|
-
mock(options)
|
8
|
-
end
|
9
|
-
|
10
|
-
describe '.run_commands' do
|
11
|
-
it "fails fast if a command fails" do
|
12
|
-
server = mock(:ssh => [job(:status => 1, :command => 'exit 1', :stderr => 'FAIL WHALE')])
|
13
|
-
capture_stdout do
|
14
|
-
expect do
|
15
|
-
RelevanceRails::Provision.run_commands server
|
16
|
-
end.to raise_error SystemExit
|
17
|
-
end.should =~ /STDERR: FAIL WHALE/
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
describe '.wait_for_ssh' do
|
22
|
-
|
23
|
-
let(:server) { mock("server") }
|
24
|
-
|
25
|
-
before do
|
26
|
-
server.should_receive(:wait_for).ordered.and_return(true)
|
27
|
-
end
|
28
|
-
|
29
|
-
it 'retries if the first attempt fails' do
|
30
|
-
server.should_receive(:ssh).ordered.and_raise(Errno::ECONNREFUSED)
|
31
|
-
server.should_receive(:ssh).ordered.and_return([job(:command => 'echo')])
|
32
|
-
RelevanceRails::Provision.should_receive(:sleep).twice.with(10).and_return(10)
|
33
|
-
expect do
|
34
|
-
capture_stdout { RelevanceRails::Provision.wait_for_ssh(server) }
|
35
|
-
end.to_not raise_error
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'retries up to five times, then fails' do
|
39
|
-
server.should_receive(:ssh).ordered.exactly(5).times.and_raise(Errno::ECONNREFUSED)
|
40
|
-
RelevanceRails::Provision.should_receive(:sleep).exactly(5).times.with(10).and_return(10)
|
41
|
-
expect do
|
42
|
-
capture_stdout { RelevanceRails::Provision.wait_for_ssh(server) }
|
43
|
-
end.to raise_error SystemExit
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
describe '.apt_installs' do
|
48
|
-
it 'retries if the first attempt fails' do
|
49
|
-
server = mock("server")
|
50
|
-
server.should_receive(:ssh).ordered.with('sudo apt-get update').and_return([job(:command => 'sudo apt-get update')])
|
51
|
-
server.should_receive(:ssh).ordered.with('sudo apt-get -y install ruby').and_return([job(:status => 1, :command => 'sudo apt-get -y install ruby')])
|
52
|
-
server.should_receive(:ssh).ordered.with('sudo apt-get update').and_return([job(:command => 'sudo apt-get update')])
|
53
|
-
server.should_receive(:ssh).ordered.with('sudo apt-get -y install ruby').and_return([job(:command => 'sudo apt-get -y install ruby')])
|
54
|
-
server.should_receive(:ssh).ordered.with('sudo apt-get -y install rubygems1.8').and_return([job(:command => 'sudo apt-get -y install rubygems1.8')])
|
55
|
-
expect do
|
56
|
-
capture_stdout { RelevanceRails::Provision.apt_installs(server) }
|
57
|
-
end.to_not raise_error
|
58
|
-
end
|
59
|
-
|
60
|
-
it 'tries twice, then fails' do
|
61
|
-
server = mock("server")
|
62
|
-
server.should_receive(:ssh).exactly(3).with('sudo apt-get update').and_return([job(:status => 1, :command => 'sudo apt-get update')])
|
63
|
-
expect do
|
64
|
-
capture_stdout { RelevanceRails::Provision.apt_installs(server) }
|
65
|
-
end.to raise_error SystemExit
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|