engineyard-local 0.2.1 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. data/Gemfile +1 -0
  2. data/Gemfile.lock +73 -1
  3. data/README.md +40 -38
  4. data/config/dna.json +92 -66
  5. data/config/locales/en.yml +94 -9
  6. data/config/patches/chef-ey-1.1.336.patch +55 -0
  7. data/config/settings.yml +6 -1
  8. data/engineyard-local.gemspec +5 -4
  9. data/install/osx/README.md +42 -4
  10. data/install/osx/engineyard-local/engineyard-local.pkgproj +35 -6
  11. data/install/osx/images/dmg_background.png +0 -0
  12. data/install/osx/images/dmg_icon.icns +0 -0
  13. data/lib/engineyard-local.rb +64 -0
  14. data/lib/engineyard-local/command.rb +23 -0
  15. data/lib/engineyard-local/command/base.rb +78 -1
  16. data/lib/engineyard-local/command/group.rb +70 -6
  17. data/lib/engineyard-local/command/help.rb +36 -0
  18. data/lib/engineyard-local/command/helpers.rb +12 -0
  19. data/lib/engineyard-local/command/start.rb +26 -0
  20. data/lib/engineyard-local/command/status.rb +33 -0
  21. data/lib/engineyard-local/command/stop.rb +26 -0
  22. data/lib/engineyard-local/command/terminate.rb +26 -0
  23. data/lib/engineyard-local/command/up.rb +24 -15
  24. data/lib/engineyard-local/command/update.rb +42 -0
  25. data/lib/engineyard-local/middleware.rb +1 -0
  26. data/lib/engineyard-local/middleware/bundle.rb +1 -0
  27. data/lib/engineyard-local/middleware/chef.rb +52 -2
  28. data/lib/engineyard-local/middleware/cookbooks.rb +111 -0
  29. data/lib/engineyard-local/middleware/dna.rb +6 -4
  30. data/lib/engineyard-local/middleware/exec.rb +2 -1
  31. data/lib/engineyard-local/middleware/helpers/executable.rb +14 -2
  32. data/lib/engineyard-local/middleware/network.rb +3 -3
  33. data/lib/engineyard-local/middleware/rails.rb +1 -0
  34. data/lib/engineyard-local/middleware/rails/assets.rb +35 -0
  35. data/lib/engineyard-local/middleware/rails/command.rb +1 -1
  36. data/lib/engineyard-local/middleware/rails/db.rb +0 -1
  37. data/lib/engineyard-local/middleware/rails/new.rb +1 -1
  38. data/lib/engineyard-local/version.rb +1 -1
  39. data/test/engineyard-local/command/up_test.rb +1 -0
  40. data/test/integration/commands_test.rb +30 -0
  41. data/test/test_helper.rb +8 -2
  42. metadata +81 -70
  43. data/install/osx/images/eylocal_installer.png +0 -0
  44. 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.bz2; sudo mkdir -p /etc/chef/recipes && cd /etc/chef/recipes && sudo tar -xjf /tmp/chef.tar.bz2; rm /tmp/chef.tar.bz2; fi"
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
- Local.config[:box_defaults][:cookbook_uri]
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
- "sudo mv #{solo_tmp_to} #{solo_to}",
49
- "sudo mv #{dna_tmp_to} #{dna_to}",
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
- "/tmp/dna.json.#{$$}"
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
- "/tmp/solo.rb.#{$$}"
72
+ File.join(Engineyard::Local.tmp_dir,"solo.rb.#{$$}")
71
73
  end
72
74
 
73
75
  def solo_to
@@ -15,7 +15,8 @@ module Engineyard
15
15
  end
16
16
 
17
17
  def commands
18
- rvm_env + [ "cd #{project_dir}", command_args ]
18
+ rvm_env +
19
+ [ "cd #{project_dir}", command_args ]
19
20
  end
20
21
 
21
22
  def command_args
@@ -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", "N"].include?(result ||= nil)
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
@@ -1,3 +1,4 @@
1
1
  require "engineyard-local/middleware/rails/db"
2
+ require "engineyard-local/middleware/rails/assets"
2
3
  require "engineyard-local/middleware/rails/command"
3
4
  require "engineyard-local/middleware/rails/install"
@@ -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,7 +16,7 @@ module Engineyard
16
16
  end
17
17
 
18
18
  def commands
19
- rvm_env +
19
+ #rvm_env +
20
20
  [ "cd #{project_dir}",
21
21
  "rails #{command_args}" ]
22
22
  end
@@ -18,7 +18,6 @@ module Engineyard
18
18
  end
19
19
 
20
20
  def commands
21
- rvm_env +
22
21
  [ "cd #{project_dir}",
23
22
  if_task_exists("db:create"),
24
23
  if_task_exists("db:migrate") ]
@@ -16,7 +16,7 @@ module Engineyard
16
16
  end
17
17
 
18
18
  def commands
19
- rvm_env +
19
+ #rvm_env +
20
20
  [ "cd #{project_dir}",
21
21
  "rails #{command_args}" ]
22
22
  end
@@ -1,5 +1,5 @@
1
1
  module Engineyard
2
2
  module Local
3
- VERSION = "0.2.1"
3
+ VERSION = "1.0.1"
4
4
  end
5
5
  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