knife-solo 0.0.15 → 0.1.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. data/CHANGELOG.md +216 -0
  2. data/LICENSE +7 -0
  3. data/README.rdoc +127 -0
  4. data/Rakefile +31 -0
  5. data/lib/chef/knife/cook.rb +4 -131
  6. data/lib/chef/knife/kitchen.rb +4 -49
  7. data/lib/chef/knife/prepare.rb +4 -50
  8. data/lib/chef/knife/solo_bootstrap.rb +51 -0
  9. data/lib/chef/knife/solo_clean.rb +25 -0
  10. data/lib/chef/knife/solo_cook.rb +137 -0
  11. data/lib/chef/knife/solo_init.rb +59 -0
  12. data/lib/chef/knife/solo_prepare.rb +56 -0
  13. data/lib/chef/knife/wash_up.rb +4 -15
  14. data/lib/knife-solo/bootstraps.rb +1 -1
  15. data/lib/knife-solo/bootstraps/linux.rb +6 -4
  16. data/lib/knife-solo/bootstraps/sun_os.rb +9 -0
  17. data/lib/knife-solo/deprecated_command.rb +19 -0
  18. data/lib/knife-solo/info.rb +1 -1
  19. data/lib/knife-solo/kitchen_command.rb +5 -10
  20. data/lib/knife-solo/node_config_command.rb +17 -3
  21. data/lib/knife-solo/ssh_command.rb +3 -3
  22. data/test/bootstraps_test.rb +90 -0
  23. data/test/deprecated_command_test.rb +46 -0
  24. data/test/integration/cases/apache2_bootstrap.rb +15 -0
  25. data/test/integration/cases/apache2_cook.rb +28 -0
  26. data/test/integration/cases/empty_cook.rb +8 -0
  27. data/test/integration/cases/encrypted_data_bag.rb +27 -0
  28. data/test/integration/centos5_6_test.rb +19 -0
  29. data/test/integration/gentoo2011_test.rb +18 -0
  30. data/test/integration/omnios_r151004_test.rb +14 -0
  31. data/test/integration/scientific_linux_63_test.rb +15 -0
  32. data/test/integration/sles_11_test.rb +14 -0
  33. data/test/integration/ubuntu10_04_test.rb +15 -0
  34. data/test/integration/ubuntu12_04_bootstrap_test.rb +17 -0
  35. data/test/integration/ubuntu12_04_test.rb +15 -0
  36. data/test/integration_helper.rb +16 -0
  37. data/test/kitchen_command_test.rb +31 -0
  38. data/test/minitest/parallel.rb +41 -0
  39. data/test/node_config_command_test.rb +101 -0
  40. data/test/solo_bootstrap_test.rb +32 -0
  41. data/test/solo_clean_test.rb +12 -0
  42. data/test/solo_cook_test.rb +67 -0
  43. data/test/solo_init_test.rb +40 -0
  44. data/test/solo_prepare_test.rb +50 -0
  45. data/test/ssh_command_test.rb +100 -0
  46. data/test/support/config.yml.example +4 -0
  47. data/test/support/data_bag_key +1 -0
  48. data/test/support/ec2_runner.rb +122 -0
  49. data/test/support/integration_test.rb +94 -0
  50. data/test/support/issue_files/gentoo2011 +3 -0
  51. data/test/support/issue_files/sles11-sp1 +4 -0
  52. data/test/support/issue_files/ubuntu +2 -0
  53. data/test/support/kitchen_helper.rb +22 -0
  54. data/test/support/loggable.rb +18 -0
  55. data/test/support/secret_cookbook/metadata.rb +5 -0
  56. data/test/support/secret_cookbook/recipes/default.rb +8 -0
  57. data/test/support/ssh_config +3 -0
  58. data/test/support/test_case.rb +24 -0
  59. data/test/support/validation_helper.rb +39 -0
  60. data/test/test_helper.rb +7 -0
  61. metadata +99 -11
  62. data/lib/knife-solo/knife_solo_error.rb +0 -3
@@ -1,55 +1,10 @@
1
- require 'chef/knife'
1
+ require 'chef/knife/solo_init'
2
+ require 'knife-solo/deprecated_command'
2
3
 
3
4
  class Chef
4
5
  class Knife
5
- class Kitchen < Knife
6
- include FileUtils
7
-
8
- deps do
9
- require 'knife-solo/knife_solo_error'
10
- end
11
-
12
- banner "knife kitchen NAME or initialize current directory with '.'"
13
-
14
- def run
15
- raise KnifeSolo::KnifeSoloError.new(banner) unless base = @name_args.first
16
-
17
- create_kitchen base
18
- create_cupboards base, %w(nodes roles data_bags site-cookbooks cookbooks)
19
- create_solo_config base
20
- end
21
-
22
- private
23
-
24
- def create_cupboards(base, dirs)
25
- dirs.each do |dir|
26
- cupboard_dir = File.join(base, dir)
27
- unless File.exist?(cupboard_dir)
28
- mkdir cupboard_dir
29
- touch File.join(cupboard_dir, '.gitkeep')
30
- end
31
- end
32
- end
33
-
34
- def create_kitchen(base)
35
- mkdir base unless base == '.'
36
- end
37
-
38
- def create_solo_config(base)
39
- solo_file = File.join(base, 'solo.rb')
40
- return if File.exist? solo_file
41
-
42
- File.open(solo_file, 'w') do |f|
43
- f << <<-RUBY.gsub(/^ {12}/, '')
44
- file_cache_path "/tmp/chef-solo"
45
- data_bag_path "/tmp/chef-solo/data_bags"
46
- encrypted_data_bag_secret "/tmp/chef-solo/data_bag_key"
47
- cookbook_path [ "/tmp/chef-solo/site-cookbooks",
48
- "/tmp/chef-solo/cookbooks" ]
49
- role_path "/tmp/chef-solo/roles"
50
- RUBY
51
- end
52
- end
6
+ class Kitchen < SoloInit
7
+ include KnifeSolo::DeprecatedCommand
53
8
  end
54
9
  end
55
10
  end
@@ -1,56 +1,10 @@
1
- require 'chef/knife'
2
- require 'knife-solo/ssh_command'
3
- require 'knife-solo/kitchen_command'
4
- require 'knife-solo/node_config_command'
1
+ require 'chef/knife/solo_prepare'
2
+ require 'knife-solo/deprecated_command'
5
3
 
6
4
  class Chef
7
5
  class Knife
8
- # Approach ported from littlechef (https://github.com/tobami/littlechef)
9
- # Copyright 2010, 2011, Miquel Torres <tobami@googlemail.com>
10
- class Prepare < Knife
11
- include KnifeSolo::SshCommand
12
- include KnifeSolo::KitchenCommand
13
- include KnifeSolo::NodeConfigCommand
14
-
15
- deps do
16
- require 'knife-solo/bootstraps'
17
- KnifeSolo::SshCommand.load_deps
18
- KnifeSolo::NodeConfigCommand.load_deps
19
- end
20
-
21
- banner "knife prepare [user@]hostname [json] (options)"
22
-
23
- option :omnibus_version,
24
- :long => "--omnibus-version VERSION",
25
- :description => "The version of Omnibus to install"
26
-
27
- option :omnibus_url,
28
- :long => "--omnibus-url URL",
29
- :description => "URL to download install.sh from"
30
-
31
- option :omnibus_options,
32
- :long => "--omnibus-options \"-r -n\"",
33
- :description => "Pass options to the install.sh script"
34
-
35
- def run
36
- validate_params!
37
- super
38
- bootstrap.bootstrap!
39
- generate_node_config
40
- end
41
-
42
- def bootstrap
43
- ui.msg "Bootstrapping Chef..."
44
- KnifeSolo::Bootstraps.class_for_operating_system(operating_system()).new(self)
45
- end
46
-
47
- def operating_system
48
- @operating_system ||= run_command('uname -s').stdout.strip
49
- end
50
-
51
- def validate_params!
52
- validate_first_cli_arg_is_a_hostname!
53
- end
6
+ class Prepare < SoloPrepare
7
+ include KnifeSolo::DeprecatedCommand
54
8
  end
55
9
  end
56
10
  end
@@ -0,0 +1,51 @@
1
+ require 'chef/knife'
2
+ require 'chef/knife/solo_cook'
3
+ require 'chef/knife/solo_prepare'
4
+
5
+ require 'knife-solo/kitchen_command'
6
+ require 'knife-solo/ssh_command'
7
+
8
+ class Chef
9
+ class Knife
10
+ class SoloBootstrap < Knife
11
+ include KnifeSolo::KitchenCommand
12
+ include KnifeSolo::SshCommand
13
+
14
+ deps do
15
+ KnifeSolo::SshCommand.load_deps
16
+ SoloPrepare.load_deps
17
+ SoloCook.load_deps
18
+ end
19
+
20
+ banner "knife solo bootstrap [USER@]HOSTNAME [JSON] (options)"
21
+
22
+ # Use (some) options from prepare and cook commands
23
+ self.options = SoloPrepare.options
24
+ [:sync_only, :why_run].each { |opt| option opt, SoloCook.options[opt] }
25
+
26
+ def run
27
+ validate!
28
+
29
+ prepare = command_with_same_args(SoloPrepare)
30
+ prepare.run
31
+
32
+ cook = command_with_same_args(SoloCook)
33
+ cook.config[:skip_chef_check] = true
34
+ cook.run
35
+ end
36
+
37
+ def validate!
38
+ validate_first_cli_arg_is_a_hostname!
39
+ validate_kitchen!
40
+ end
41
+
42
+ def command_with_same_args(klass)
43
+ cmd = klass.new
44
+ cmd.ui = ui
45
+ cmd.name_args = @name_args
46
+ cmd.config = config
47
+ cmd
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,25 @@
1
+ require 'chef/knife'
2
+ require 'knife-solo/ssh_command'
3
+ require 'knife-solo/kitchen_command'
4
+
5
+ class Chef
6
+ class Knife
7
+ class SoloClean < Knife
8
+ include KnifeSolo::SshCommand
9
+ include KnifeSolo::KitchenCommand
10
+
11
+ banner "knife solo clean [USER@]HOSTNAME"
12
+
13
+ def run
14
+ validate!
15
+ Chef::Config.from_file('solo.rb')
16
+ run_command "rm -rf #{Chef::Config.file_cache_path}"
17
+ end
18
+
19
+ def validate!
20
+ validate_first_cli_arg_is_a_hostname!
21
+ validate_kitchen!
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,137 @@
1
+ require 'chef/knife'
2
+
3
+ require 'knife-solo/ssh_command'
4
+ require 'knife-solo/kitchen_command'
5
+ require 'knife-solo/node_config_command'
6
+ require 'knife-solo/tools'
7
+
8
+ class Chef
9
+ class Knife
10
+ # Approach ported from spatula (https://github.com/trotter/spatula)
11
+ # Copyright 2009, Trotter Cashion
12
+ class SoloCook < Knife
13
+ OMNIBUS_EMBEDDED_PATHS ||= ["/opt/chef/embedded/bin", "/opt/opscode/embedded/bin"]
14
+ OMNIBUS_EMBEDDED_GEM_PATHS ||= ["/opt/chef/embedded/lib/ruby/gems/1.9.1", "/opt/opscode/embedded/lib/ruby/gems/1.9.1"]
15
+ CHEF_VERSION_CONSTRAINT ||= ">=0.10.4"
16
+
17
+ include KnifeSolo::SshCommand
18
+ include KnifeSolo::KitchenCommand
19
+ include KnifeSolo::NodeConfigCommand
20
+ include KnifeSolo::Tools
21
+
22
+ deps do
23
+ require 'chef/cookbook/chefignore'
24
+ require 'pathname'
25
+ KnifeSolo::SshCommand.load_deps
26
+ KnifeSolo::NodeConfigCommand.load_deps
27
+ end
28
+
29
+ banner "knife solo cook [USER@]HOSTNAME [JSON] (options)"
30
+
31
+ option :skip_chef_check,
32
+ :long => '--skip-chef-check',
33
+ :boolean => true,
34
+ :description => "Skip the version check on the Chef gem"
35
+
36
+ option :sync_only,
37
+ :long => '--sync-only',
38
+ :boolean => false,
39
+ :description => "Only sync the cookbook - do not run Chef"
40
+
41
+ option :why_run,
42
+ :short => '-W',
43
+ :long => '--why-run',
44
+ :boolean => true,
45
+ :description => "Enable whyrun mode"
46
+
47
+ def run
48
+ time('Run') do
49
+ validate!
50
+ Chef::Config.from_file('solo.rb')
51
+ check_chef_version unless config[:skip_chef_check]
52
+ generate_node_config
53
+ rsync_kitchen
54
+ add_patches
55
+ cook unless config[:sync_only]
56
+ end
57
+ end
58
+
59
+ def validate!
60
+ validate_first_cli_arg_is_a_hostname!
61
+ validate_kitchen!
62
+ end
63
+
64
+ def chef_path
65
+ Chef::Config.file_cache_path
66
+ end
67
+
68
+ def chefignore
69
+ @chefignore ||= ::Chef::Cookbook::Chefignore.new("./")
70
+ end
71
+
72
+ # cygwin rsync path must be adjusted to work
73
+ def adjust_rsync_path(path)
74
+ return path unless windows_node?
75
+ path.gsub(/^(\w):/) { "/cygdrive/#{$1}" }
76
+ end
77
+
78
+ def patch_path
79
+ Array(Chef::Config.cookbook_path).first + "/chef_solo_patches/libraries"
80
+ end
81
+
82
+ def rsync_exclude
83
+ (%w{revision-deploys tmp '.*'} + chefignore.ignores).uniq
84
+ end
85
+
86
+ def debug?
87
+ config[:verbosity] and config[:verbosity] > 0
88
+ end
89
+
90
+ # Time a command
91
+ def time(msg)
92
+ return yield unless debug?
93
+ ui.msg "Starting '#{msg}'"
94
+ start = Time.now
95
+ yield
96
+ ui.msg "#{msg} finished in #{Time.now - start} seconds"
97
+ end
98
+
99
+ def rsync_kitchen
100
+ time('Rsync kitchen') do
101
+ cmd = %Q{rsync -rl --rsh="ssh #{ssh_args}" --delete #{rsync_exclude.collect{ |ignore| "--exclude #{ignore} " }.join} ./ :#{adjust_rsync_path(chef_path)}}
102
+ ui.msg cmd if debug?
103
+ system! cmd
104
+ end
105
+ end
106
+
107
+ def add_patches
108
+ run_portable_mkdir_p(patch_path)
109
+ Dir[Pathname.new(__FILE__).dirname.join("patches", "*.rb").to_s].each do |patch|
110
+ time(patch) do
111
+ system! %Q{rsync -rl --rsh="ssh #{ssh_args}" #{patch} :#{adjust_rsync_path(patch_path)}}
112
+ end
113
+ end
114
+ end
115
+
116
+ def check_chef_version
117
+ ui.msg "Checking Chef version..."
118
+ result = run_command <<-BASH
119
+ export PATH="#{OMNIBUS_EMBEDDED_PATHS.join(":")}:$PATH"
120
+ export GEM_PATH="#{OMNIBUS_EMBEDDED_GEM_PATHS.join(":")}:$GEM_PATH"
121
+ ruby -rubygems -e "gem 'chef', '#{CHEF_VERSION_CONSTRAINT}'"
122
+ BASH
123
+ raise "Couldn't find Chef #{CHEF_VERSION_CONSTRAINT} on #{host}. Please run `#{$0} prepare #{ssh_args}` to ensure Chef is installed and up to date." unless result.success?
124
+ end
125
+
126
+ def cook
127
+ cmd = "sudo chef-solo -c #{chef_path}/solo.rb -j #{chef_path}/#{node_config}"
128
+ cmd << " -l debug" if debug?
129
+ cmd << " -N #{config[:chef_node_name]}" if config[:chef_node_name]
130
+ cmd << " -W" if config[:why_run]
131
+
132
+ result = stream_command cmd
133
+ raise "chef-solo failed. See output above." unless result.success?
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,59 @@
1
+ require 'chef/knife'
2
+
3
+ class Chef
4
+ class Knife
5
+ class SoloInit < Knife
6
+ include FileUtils
7
+
8
+ banner "knife solo init DIRECTORY"
9
+
10
+ def run
11
+ validate!
12
+ base = @name_args.first
13
+ create_kitchen base
14
+ create_cupboards base, %w(nodes roles data_bags site-cookbooks cookbooks)
15
+ create_solo_config base
16
+ end
17
+
18
+ def validate!
19
+ unless @name_args.first
20
+ show_usage
21
+ ui.fatal "You must specify a directory. Use '.' to initialize the current one."
22
+ exit 1
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def create_cupboards(base, dirs)
29
+ dirs.each do |dir|
30
+ cupboard_dir = File.join(base, dir)
31
+ unless File.exist?(cupboard_dir)
32
+ mkdir cupboard_dir
33
+ touch File.join(cupboard_dir, '.gitkeep')
34
+ end
35
+ end
36
+ end
37
+
38
+ def create_kitchen(base)
39
+ mkdir base unless base == '.'
40
+ end
41
+
42
+ def create_solo_config(base)
43
+ solo_file = File.join(base, 'solo.rb')
44
+ return if File.exist? solo_file
45
+
46
+ File.open(solo_file, 'w') do |f|
47
+ f << <<-RUBY.gsub(/^ {12}/, '')
48
+ file_cache_path "/tmp/chef-solo"
49
+ data_bag_path "/tmp/chef-solo/data_bags"
50
+ encrypted_data_bag_secret "/tmp/chef-solo/data_bag_key"
51
+ cookbook_path [ "/tmp/chef-solo/site-cookbooks",
52
+ "/tmp/chef-solo/cookbooks" ]
53
+ role_path "/tmp/chef-solo/roles"
54
+ RUBY
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,56 @@
1
+ require 'chef/knife'
2
+ require 'knife-solo/ssh_command'
3
+ require 'knife-solo/kitchen_command'
4
+ require 'knife-solo/node_config_command'
5
+
6
+ class Chef
7
+ class Knife
8
+ # Approach ported from littlechef (https://github.com/tobami/littlechef)
9
+ # Copyright 2010, 2011, Miquel Torres <tobami@googlemail.com>
10
+ class SoloPrepare < Knife
11
+ include KnifeSolo::SshCommand
12
+ include KnifeSolo::KitchenCommand
13
+ include KnifeSolo::NodeConfigCommand
14
+
15
+ deps do
16
+ require 'knife-solo/bootstraps'
17
+ KnifeSolo::SshCommand.load_deps
18
+ KnifeSolo::NodeConfigCommand.load_deps
19
+ end
20
+
21
+ banner "knife solo prepare [USER@]HOSTNAME [JSON] (options)"
22
+
23
+ option :omnibus_version,
24
+ :long => "--omnibus-version VERSION",
25
+ :description => "The version of Omnibus to install"
26
+
27
+ option :omnibus_url,
28
+ :long => "--omnibus-url URL",
29
+ :description => "URL to download install.sh from"
30
+
31
+ option :omnibus_options,
32
+ :long => "--omnibus-options \"-r -n\"",
33
+ :description => "Pass options to the install.sh script"
34
+
35
+ def run
36
+ validate!
37
+ bootstrap.bootstrap!
38
+ generate_node_config
39
+ end
40
+
41
+ def validate!
42
+ validate_first_cli_arg_is_a_hostname!
43
+ validate_kitchen!
44
+ end
45
+
46
+ def bootstrap
47
+ ui.msg "Bootstrapping Chef..."
48
+ KnifeSolo::Bootstraps.class_for_operating_system(operating_system()).new(self)
49
+ end
50
+
51
+ def operating_system
52
+ @operating_system ||= run_command('uname -s').stdout.strip
53
+ end
54
+ end
55
+ end
56
+ end