engineyard-local 0.2.1 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -0
- data/Gemfile.lock +73 -1
- data/README.md +40 -38
- data/config/dna.json +92 -66
- data/config/locales/en.yml +94 -9
- data/config/patches/chef-ey-1.1.336.patch +55 -0
- data/config/settings.yml +6 -1
- data/engineyard-local.gemspec +5 -4
- data/install/osx/README.md +42 -4
- data/install/osx/engineyard-local/engineyard-local.pkgproj +35 -6
- data/install/osx/images/dmg_background.png +0 -0
- data/install/osx/images/dmg_icon.icns +0 -0
- data/lib/engineyard-local.rb +64 -0
- data/lib/engineyard-local/command.rb +23 -0
- data/lib/engineyard-local/command/base.rb +78 -1
- data/lib/engineyard-local/command/group.rb +70 -6
- data/lib/engineyard-local/command/help.rb +36 -0
- data/lib/engineyard-local/command/helpers.rb +12 -0
- data/lib/engineyard-local/command/start.rb +26 -0
- data/lib/engineyard-local/command/status.rb +33 -0
- data/lib/engineyard-local/command/stop.rb +26 -0
- data/lib/engineyard-local/command/terminate.rb +26 -0
- data/lib/engineyard-local/command/up.rb +24 -15
- data/lib/engineyard-local/command/update.rb +42 -0
- data/lib/engineyard-local/middleware.rb +1 -0
- data/lib/engineyard-local/middleware/bundle.rb +1 -0
- data/lib/engineyard-local/middleware/chef.rb +52 -2
- data/lib/engineyard-local/middleware/cookbooks.rb +111 -0
- data/lib/engineyard-local/middleware/dna.rb +6 -4
- data/lib/engineyard-local/middleware/exec.rb +2 -1
- data/lib/engineyard-local/middleware/helpers/executable.rb +14 -2
- data/lib/engineyard-local/middleware/network.rb +3 -3
- data/lib/engineyard-local/middleware/rails.rb +1 -0
- data/lib/engineyard-local/middleware/rails/assets.rb +35 -0
- data/lib/engineyard-local/middleware/rails/command.rb +1 -1
- data/lib/engineyard-local/middleware/rails/db.rb +0 -1
- data/lib/engineyard-local/middleware/rails/new.rb +1 -1
- data/lib/engineyard-local/version.rb +1 -1
- data/test/engineyard-local/command/up_test.rb +1 -0
- data/test/integration/commands_test.rb +30 -0
- data/test/test_helper.rb +8 -2
- metadata +81 -70
- data/install/osx/images/eylocal_installer.png +0 -0
- data/test/integration/up_test.rb +0 -28
@@ -0,0 +1,42 @@
|
|
1
|
+
module Engineyard
|
2
|
+
module Local
|
3
|
+
module Command
|
4
|
+
class Update < Base
|
5
|
+
|
6
|
+
def exec(*args)
|
7
|
+
installed_cookbook_version = []
|
8
|
+
la_brea_data = []
|
9
|
+
run( Vagrant::Action::Builder.new do
|
10
|
+
use( Engineyard::Local::Middleware::Cookbooks,:get_installed_version, installed_cookbook_version )
|
11
|
+
use( Engineyard::Local::Middleware::Cookbooks,:get_la_brea_data, la_brea_data )
|
12
|
+
end )
|
13
|
+
|
14
|
+
installed_cookbook_version = installed_cookbook_version.first
|
15
|
+
la_brea_data = la_brea_data.first
|
16
|
+
|
17
|
+
if ( installed_cookbook_version == la_brea_data[:cookbooks_version] )
|
18
|
+
@env.ui.info I18n.t("eylocal.update.nothing")
|
19
|
+
else
|
20
|
+
@env.ui.info I18n.t("eylocal.update.updating")
|
21
|
+
|
22
|
+
new_cookbook_version = []
|
23
|
+
run( Vagrant::Action::Builder.new do
|
24
|
+
use( Engineyard::Local::Middleware::Cookbooks,:update_cookbooks )
|
25
|
+
use( Engineyard::Local::Middleware::Cookbooks,:get_installed_version, new_cookbook_version )
|
26
|
+
end )
|
27
|
+
new_cookbook_version = new_cookbook_version.first
|
28
|
+
|
29
|
+
if (installed_cookbook_version == new_cookbook_version)
|
30
|
+
@env.ui.info I18n.t("eylocal.update.fail")
|
31
|
+
else
|
32
|
+
@env.ui.info I18n.t("eylocal.update.success")
|
33
|
+
run Engineyard::Local::Command::Up.setup_stack(options)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -5,6 +5,7 @@ require "engineyard-local/middleware/rails"
|
|
5
5
|
require "engineyard-local/middleware/exec"
|
6
6
|
require "engineyard-local/middleware/tag"
|
7
7
|
require "engineyard-local/middleware/network"
|
8
|
+
require "engineyard-local/middleware/cookbooks"
|
8
9
|
require "engineyard-local/middleware/default_provisioner"
|
9
10
|
|
10
11
|
# alter some of the core vagrant middleware stacks to make sure
|
@@ -23,6 +23,7 @@ module Engineyard
|
|
23
23
|
"cd #{project_dir}",
|
24
24
|
"sudo mkdir -p #{project_dir} /data/#{Engineyard::Local.config['app_name']}/",
|
25
25
|
"if [[ ! -e /data/#{Engineyard::Local.config['app_name']}/current ]]; then sudo ln -sf #{project_dir} /data/#{Engineyard::Local.config['app_name']}/current; fi",
|
26
|
+
"if [[ ! -e /data/#{Engineyard::Local.config['app_name']}/current/public ]]; then sudo mkdir -p /data/#{Engineyard::Local.config['app_name']}/current/public; fi",
|
26
27
|
if_gemfile_exists("sudo bundle install")
|
27
28
|
]
|
28
29
|
end
|
@@ -2,6 +2,7 @@ module Engineyard
|
|
2
2
|
module Local
|
3
3
|
module Middleware
|
4
4
|
class Chef
|
5
|
+
include Middleware::Helpers::Uploadable
|
5
6
|
include Middleware::Helpers::Executable
|
6
7
|
include Middleware::Helpers::Rvm
|
7
8
|
|
@@ -12,22 +13,38 @@ module Engineyard
|
|
12
13
|
|
13
14
|
def call(env)
|
14
15
|
@env[:ui].info I18n.t("eylocal.setup.chef")
|
16
|
+
copy_patches(env)
|
15
17
|
ssh_exec!(env, commands)
|
16
18
|
@app.call(env)
|
17
19
|
end
|
18
20
|
|
21
|
+
def cached_data_path
|
22
|
+
"#{@env[:root_path]}/.ey_local_data"
|
23
|
+
end
|
24
|
+
|
25
|
+
def copy_patches(env)
|
26
|
+
patchdir = "/tmp/eylocal_patches"
|
27
|
+
ssh_exec!(env, ["mkdir -p #{patchdir}"])
|
28
|
+
|
29
|
+
Local.config[:box_defaults][:patches].each do |p|
|
30
|
+
from = File.expand_path("config/patches/#{p}", Engineyard::Local.project_root)
|
31
|
+
ssh_upload!(env, from, File.join(patchdir,p))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
19
35
|
def commands
|
20
36
|
rvm_env +
|
21
37
|
[
|
22
38
|
ensure_that_recipes_are_installed,
|
23
39
|
"cd /etc/chef",
|
24
40
|
"sudo env PATH=/usr/local/ey_resin/bin:/sbin:/bin:/usr/sbin:/usr/bin chef-solo -j /etc/chef/dna.json -c /etc/chef/solo.rb",
|
41
|
+
"if [[ ! -e /usr/bin/rake ]]; then sudo ln -s /usr/bin/rake19 /usr/bin/rake; fi",
|
25
42
|
run_custom_chef_in_application_if_it_exists
|
26
43
|
]
|
27
44
|
end
|
28
45
|
|
29
46
|
def ensure_that_recipes_are_installed
|
30
|
-
"if [[ ! -d /etc/chef/recipes ]]; then curl -s #{cookbook_uri} > /tmp/chef.tar
|
47
|
+
"if [[ ! -d /etc/chef/recipes ]]; then curl -s #{cookbook_uri} > /tmp/chef.tar#{cookbook_suffix}; sudo mkdir -p /etc/chef/recipes && cd /etc/chef/recipes && sudo tar #{tar_flags} /tmp/chef.tar#{cookbook_suffix}; sudo patch -p1 < /tmp/eylocal_patches/* >& /dev/null; sudo touch #{Engineyard::Local::Middleware::Cookbooks::COOKBOOK_VERSION_FILE}; sudo chown vagrant #{Engineyard::Local::Middleware::Cookbooks::COOKBOOK_VERSION_FILE}; echo \"#{cookbook_version}\" > #{Engineyard::Local::Middleware::Cookbooks::COOKBOOK_VERSION_FILE}; rm /tmp/chef.tar#{cookbook_suffix}; fi"
|
31
48
|
end
|
32
49
|
|
33
50
|
def run_custom_chef_in_application_if_it_exists
|
@@ -35,7 +52,40 @@ module Engineyard
|
|
35
52
|
end
|
36
53
|
|
37
54
|
def cookbook_uri
|
38
|
-
|
55
|
+
ey_local_data = nil
|
56
|
+
if ( !@cookbook_uri && File.exist?( cached_data_path ) )
|
57
|
+
ey_local_data = YAML.load( File.read( cached_data_path ) )
|
58
|
+
end
|
59
|
+
@la_brea_data ||= ey_local_data ? ey_local_data[:la_brea_data] : nil
|
60
|
+
@cookbook_uri ||= ( ey_local_data && ey_local_data[:la_brea_data][:cookbooks_url] ) ?
|
61
|
+
ey_local_data[:la_brea_data][:cookbooks_url] : Local.config[:box_defaults][:cookbook_uri]
|
62
|
+
end
|
63
|
+
|
64
|
+
def cookbook_suffix
|
65
|
+
cookbook_uri =~ /\.(\w+)$/
|
66
|
+
case $1
|
67
|
+
when /bz2|tbz/
|
68
|
+
".bz2"
|
69
|
+
when /gz|tgz/
|
70
|
+
".gz"
|
71
|
+
else
|
72
|
+
""
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def tar_flags
|
77
|
+
case cookbook_suffix
|
78
|
+
when /bz2|tbz/
|
79
|
+
"-xjf"
|
80
|
+
when /gz|tgz/
|
81
|
+
"-xzf"
|
82
|
+
else
|
83
|
+
"-xf"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def cookbook_version
|
88
|
+
( @la_brea_data && @la_brea_data[:cookbooks_version] ) ? @la_brea_data[:cookbooks_version] : Local.config[:box_defaults][:cookbook_version]
|
39
89
|
end
|
40
90
|
|
41
91
|
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
|
3
|
+
module Engineyard
|
4
|
+
module Local
|
5
|
+
module Middleware
|
6
|
+
class Cookbooks
|
7
|
+
include Middleware::Helpers::Executable
|
8
|
+
include Middleware::Helpers::Rvm
|
9
|
+
extend Middleware::Helpers::Executable
|
10
|
+
|
11
|
+
DATA_EXPIRATION = 600
|
12
|
+
COOKBOOK_VERSION_FILE = "/etc/chef/ey_local_cookbook_version"
|
13
|
+
|
14
|
+
def cookbook_query_commands
|
15
|
+
[
|
16
|
+
"cat #{COOKBOOK_VERSION_FILE}"
|
17
|
+
]
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(app, env, *args)
|
21
|
+
@app = app
|
22
|
+
@env = env
|
23
|
+
@args = args
|
24
|
+
end
|
25
|
+
|
26
|
+
def cached_data_path
|
27
|
+
"#{@env[:root_path]}/.ey_local_data"
|
28
|
+
end
|
29
|
+
|
30
|
+
def call(env)
|
31
|
+
cmd,response = @args
|
32
|
+
|
33
|
+
if File.exist?(cached_data_path)
|
34
|
+
ey_local_data = YAML.load(File.read(cached_data_path))
|
35
|
+
else
|
36
|
+
ey_local_data = {
|
37
|
+
:installed_cookbook_version => {
|
38
|
+
:data => nil,
|
39
|
+
:as_of => Time.at(1)
|
40
|
+
},
|
41
|
+
:la_brea_data => {
|
42
|
+
:changelog => nil,
|
43
|
+
:cookbooks_url => nil,
|
44
|
+
:cookbooks_version => nil,
|
45
|
+
:created_at => nil,
|
46
|
+
:updated_at => nil,
|
47
|
+
:uuid => nil,
|
48
|
+
:as_of => Time.at(1)
|
49
|
+
}
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
case cmd
|
54
|
+
when :get_installed_version
|
55
|
+
get_installed_cookbook_version(ey_local_data)
|
56
|
+
response << ey_local_data[:installed_cookbook_version][:data]
|
57
|
+
|
58
|
+
when :get_la_brea_data
|
59
|
+
get_la_brea_data(ey_local_data)
|
60
|
+
response << ey_local_data[:la_brea_data]
|
61
|
+
|
62
|
+
when :update_cookbooks
|
63
|
+
get_la_brea_data(ey_local_data)
|
64
|
+
|
65
|
+
ssh_exec!(@env, update_cookbook_commands(
|
66
|
+
ey_local_data[:la_brea_data][:cookbooks_url],
|
67
|
+
ey_local_data[:la_brea_data][:cookbooks_version]))
|
68
|
+
get_installed_cookbook_version(ey_local_data, true)
|
69
|
+
end
|
70
|
+
|
71
|
+
@app.call(env)
|
72
|
+
end
|
73
|
+
|
74
|
+
def get_installed_cookbook_version(ey_local_data, force = false)
|
75
|
+
if ( force || ( Time.now > ( ey_local_data[:installed_cookbook_version][:as_of] + DATA_EXPIRATION ) ) )
|
76
|
+
cmd_output = ssh_exec(@env, cookbook_query_commands, {:error_check => false})
|
77
|
+
ey_local_data[:installed_cookbook_version][:data] = cmd_output[:stdout] ? cmd_output[:stdout].join.chomp : nil
|
78
|
+
ey_local_data[:installed_cookbook_version][:as_of] = Time.now
|
79
|
+
write_cached_data(ey_local_data)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_la_brea_data(ey_local_data)
|
84
|
+
if ( Time.now > ( ey_local_data[:la_brea_data][:as_of] + DATA_EXPIRATION ) )
|
85
|
+
r = YAML.load(open("http://#{Engineyard::Local.config[:la_brea_bridge]}/stack")) rescue nil
|
86
|
+
if r
|
87
|
+
r[:as_of] = Time.now
|
88
|
+
ey_local_data[:la_brea_data] = r
|
89
|
+
write_cached_data(ey_local_data)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def write_cached_data(ey_local_data)
|
95
|
+
File.open(cached_data_path, "w+") {|fh| fh.write YAML.dump(ey_local_data)}
|
96
|
+
end
|
97
|
+
|
98
|
+
def update_cookbook_commands(cookbook_uri, cookbook_version)
|
99
|
+
rvm_env +
|
100
|
+
[
|
101
|
+
"curl -s #{cookbook_uri} > /tmp/_chef.tgz",
|
102
|
+
"sudo mkdir -p /etc/chef/recipes && cd /etc/chef/recipes && sudo tar -xzf /tmp/_chef.tgz",
|
103
|
+
"if (( ! $? )); then sudo chown \`whoami\` #{COOKBOOK_VERSION_FILE}; echo \"#{cookbook_version}\" > #{COOKBOOK_VERSION_FILE}; fi",
|
104
|
+
"rm /tmp/_chef.tgz"
|
105
|
+
]
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -45,8 +45,10 @@ module Engineyard
|
|
45
45
|
|
46
46
|
def commands
|
47
47
|
[
|
48
|
-
|
49
|
-
|
48
|
+
# Windows slashes are eliminated when these commands are
|
49
|
+
# passed, so we need to ensure they are correctly escaped.
|
50
|
+
"sudo mv #{solo_tmp_to.gsub("\\","\\\\\\")} #{solo_to}",
|
51
|
+
"sudo mv #{dna_tmp_to.gsub("\\","\\\\\\")} #{dna_to}",
|
50
52
|
]
|
51
53
|
end
|
52
54
|
|
@@ -55,7 +57,7 @@ module Engineyard
|
|
55
57
|
end
|
56
58
|
|
57
59
|
def dna_tmp_to
|
58
|
-
"
|
60
|
+
File.join(Engineyard::Local.tmp_dir,"dna.json.#{$$}")
|
59
61
|
end
|
60
62
|
|
61
63
|
def dna_to
|
@@ -67,7 +69,7 @@ module Engineyard
|
|
67
69
|
end
|
68
70
|
|
69
71
|
def solo_tmp_to
|
70
|
-
"
|
72
|
+
File.join(Engineyard::Local.tmp_dir,"solo.rb.#{$$}")
|
71
73
|
end
|
72
74
|
|
73
75
|
def solo_to
|
@@ -9,13 +9,25 @@ module Engineyard
|
|
9
9
|
|
10
10
|
env[:vm].channel.execute(commands) do |stream, data|
|
11
11
|
if stream == :stdout
|
12
|
-
env[:vm].ui.info(data.strip)
|
12
|
+
env[:vm].ui.info(data.strip, opts)
|
13
13
|
else
|
14
|
-
env[:vm].ui.error(data.strip)
|
14
|
+
env[:vm].ui.error(data.strip, opts)
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
+
def ssh_exec(env, bash_commands, opts = {})
|
20
|
+
commands = bash_commands.join(";\n")
|
21
|
+
|
22
|
+
r = Hash.new {|h,k| h[k] = []}
|
23
|
+
|
24
|
+
env[:vm].channel.execute(commands, opts) do |stream, data|
|
25
|
+
r[stream] << data
|
26
|
+
end
|
27
|
+
|
28
|
+
r
|
29
|
+
end
|
30
|
+
|
19
31
|
# TODO might belong in a general helpers mixin
|
20
32
|
def project_dir
|
21
33
|
@env[:vm].config.vm.shared_folders["v-root"][:guestpath]
|
@@ -19,17 +19,17 @@ module Engineyard
|
|
19
19
|
# if the proposed ip matches a different vms tagged ip
|
20
20
|
# let the user decide if this is intended or needs to be fixed
|
21
21
|
if(!@options[:silent] && existing_ip == proposed_ip)
|
22
|
-
while !["Y",
|
22
|
+
while !["Y","y","N","n"].include?(result ||= nil)
|
23
23
|
result = check_with_user(name)
|
24
24
|
end
|
25
25
|
|
26
|
-
if result == "N"
|
26
|
+
if result.upcase == "N"
|
27
27
|
raise(Errors::PossibleIPCollision,
|
28
28
|
:proposed_ip => proposed_ip,
|
29
29
|
:vm_name => name)
|
30
30
|
end
|
31
31
|
|
32
|
-
if result == "Y"
|
32
|
+
if result.upcase == "Y"
|
33
33
|
break
|
34
34
|
end
|
35
35
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Engineyard
|
2
|
+
module Local
|
3
|
+
module Middleware
|
4
|
+
module Rails
|
5
|
+
class Assets
|
6
|
+
include Middleware::Helpers::Rvm
|
7
|
+
include Middleware::Helpers::Executable
|
8
|
+
|
9
|
+
def initialize(app, env)
|
10
|
+
@app = app
|
11
|
+
@env = env
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
@env[:ui].info I18n.t("eylocal.setup.rails.assets")
|
16
|
+
ssh_exec!(env, commands)
|
17
|
+
@app.call(env)
|
18
|
+
end
|
19
|
+
|
20
|
+
def commands
|
21
|
+
[ "cd #{project_dir}",
|
22
|
+
if_task_exists("assets:precompile"),
|
23
|
+
"sudo /etc/init.d/nginx restart" ]
|
24
|
+
end
|
25
|
+
|
26
|
+
# if there's a Rakefile, and rake -T contains the task we're looking for
|
27
|
+
# execute the task
|
28
|
+
def if_task_exists(task)
|
29
|
+
"if [[ `rake -T > /dev/null 2>&1 && rake -T | grep -e '#{task}'` ]]; then rake #{task}; fi"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -16,6 +16,7 @@ class CommandUpTest < Test::Unit::TestCase
|
|
16
16
|
# prevent the bundle middleware from executing
|
17
17
|
@klass.any_instance.stubs(:with_target_vms).returns([])
|
18
18
|
@klass.any_instance.stubs(:env).returns(@env)
|
19
|
+
@klass.any_instance.stubs(:pwd_matches_root_path).returns(true)
|
19
20
|
|
20
21
|
@env.stubs(:cli)
|
21
22
|
@env.stubs(:root_path).returns(nil)
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
module Integration
|
4
|
+
class CommandsTest < Test::Unit::TestCase
|
5
|
+
include Engineyard::Local::TestHelpers::Integration
|
6
|
+
|
7
|
+
def setup
|
8
|
+
Dir.chdir(ensure_test_directory)
|
9
|
+
fail_on_stderr
|
10
|
+
clean_env
|
11
|
+
end
|
12
|
+
|
13
|
+
# TODO cramming it all in here to ensure sequence
|
14
|
+
should "up completes as do dependent commands" do
|
15
|
+
assert_cmd("ey-local up --silent")
|
16
|
+
assert(`ey-local list` != "", "the output should not be empty")
|
17
|
+
assert(`ey-local exec echo "foo"`.include?("foo"), "output should include the echo value")
|
18
|
+
|
19
|
+
log_setup
|
20
|
+
assert(`ey-local log`.strip == "dev", "log output default should come from dev log without prefix")
|
21
|
+
assert(`ey-local log --environment=production`.strip == "prod", "log output default should come from dev log without prefix")
|
22
|
+
assert_cmd("ey-local destroy -f")
|
23
|
+
end
|
24
|
+
|
25
|
+
def log_setup
|
26
|
+
`echo "dev" > log/development.log`
|
27
|
+
`echo "prod" > log/production.log`
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|