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,21 +1,10 @@
1
- require 'chef/knife'
2
- require 'knife-solo/ssh_command'
3
- require 'knife-solo/kitchen_command'
1
+ require 'chef/knife/solo_clean'
2
+ require 'knife-solo/deprecated_command'
4
3
 
5
4
  class Chef
6
5
  class Knife
7
- class WashUp < Knife
8
- include KnifeSolo::SshCommand
9
- include KnifeSolo::KitchenCommand
10
-
11
- banner "knife wash_up [user@]hostname"
12
-
13
- def run
14
- validate_first_cli_arg_is_a_hostname!
15
- super
16
- Chef::Config.from_file('solo.rb')
17
- run_command "rm -rf #{Chef::Config.file_cache_path}"
18
- end
6
+ class WashUp < SoloClean
7
+ include KnifeSolo::DeprecatedCommand
19
8
  end
20
9
  end
21
10
  end
@@ -112,7 +112,7 @@ module KnifeSolo
112
112
  include KnifeSolo::Bootstraps::InstallCommands
113
113
 
114
114
  def initialize(prepare)
115
- # instance of Chef::Knife::Prepare
115
+ # instance of Chef::Knife::SoloPrepare
116
116
  @prepare = prepare
117
117
  end
118
118
 
@@ -96,14 +96,16 @@ module KnifeSolo::Bootstraps
96
96
  {:type => "omnibus", :version => "FC15"}
97
97
  when %r{Fedora release.*? 16}
98
98
  {:type => "omnibus", :version => "FC16"}
99
+ when %r{Fedora release.*? 17}
100
+ {:type => "omnibus", :version => "FC17"}
99
101
  when %r{Scientific Linux.*? 5}
100
102
  {:type => "omnibus", :version => "RHEL5"}
101
103
  when %r{Scientific Linux.*? 6}
102
104
  {:type => "yum_omnibus", :version => "RHEL6"}
103
- when %r{SUSE Linux Enterprise Server 11 SP1}
104
- {:type => "zypper_gem", :version => "SLES11"}
105
- when %r{openSUSE 11.4}
106
- {:type => "zypper_gem", :version => "openSUSE"}
105
+ when %r{SUSE Linux Enterprise Server 1[12]}
106
+ {:type => "omnibus", :version => "SLES11"}
107
+ when %r{openSUSE 1[12]}
108
+ {:type => "omnibus", :version => "openSUSE"}
107
109
  when %r{This is \\n\.\\O \(\\s \\m \\r\) \\t}
108
110
  {:type => "emerge_gem", :version => "Gentoo"}
109
111
  else
@@ -0,0 +1,9 @@
1
+ module KnifeSolo::Bootstraps
2
+ class SunOS < Base
3
+ def bootstrap!
4
+ stream_command "sudo pkg install network/rsync web/ca-bundle"
5
+ stream_command "sudo bash -c 'echo ca_certificate=/etc/cacert.pem >> /etc/wgetrc'"
6
+ omnibus_install
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ module KnifeSolo
2
+ module DeprecatedCommand
3
+
4
+ def self.included(other)
5
+ other.class_eval do
6
+ def self.deprecated
7
+ "`knife #{common_name}` is deprecated! Please use:\n #{superclass.banner}"
8
+ end
9
+
10
+ banner deprecated
11
+ end
12
+ end
13
+
14
+ def run
15
+ ui.warn self.class.deprecated
16
+ super
17
+ end
18
+ end
19
+ end
@@ -1,5 +1,5 @@
1
1
  module KnifeSolo
2
2
  def self.version
3
- '0.0.15'
3
+ '0.1.0.pre1'
4
4
  end
5
5
  end
@@ -1,19 +1,14 @@
1
- require 'knife-solo/knife_solo_error'
2
-
3
1
  module KnifeSolo
4
2
  module KitchenCommand
5
- class OutOfKitchenError < KnifeSoloError
6
- def message
7
- "This command must be run inside a Chef solo kitchen."
8
- end
9
- end
10
-
11
3
  def self.required_files
12
4
  %w(solo.rb)
13
5
  end
14
6
 
15
- def run
16
- raise OutOfKitchenError.new unless required_files_present?
7
+ def validate_kitchen!
8
+ unless required_files_present?
9
+ ui.fatal "This command must be run inside a Chef solo kitchen."
10
+ exit 1
11
+ end
17
12
  end
18
13
 
19
14
  def required_files_present?
@@ -15,6 +15,20 @@ module KnifeSolo
15
15
  :short => "-N NAME",
16
16
  :long => "--node-name NAME",
17
17
  :description => "The Chef node name for your new node"
18
+
19
+ option :run_list,
20
+ :short => "-r RUN_LIST",
21
+ :long => "--run-list RUN_LIST",
22
+ :description => "Comma separated list of roles/recipes to put to node config (if it does not exist)",
23
+ :proc => lambda { |o| o.split(/[\s,]+/) },
24
+ :default => []
25
+
26
+ option :first_boot_attributes,
27
+ :short => "-j JSON_ATTRIBS",
28
+ :long => "--json-attributes",
29
+ :description => "A JSON string to be added to node config (if it does not exist)",
30
+ :proc => lambda { |o| JSON.parse(o) },
31
+ :default => {}
18
32
  end
19
33
  end
20
34
 
@@ -29,9 +43,9 @@ module KnifeSolo
29
43
  else
30
44
  ui.msg "Generating node config '#{node_config}'..."
31
45
  File.open(node_config, 'w') do |f|
32
- f.print <<-JSON.gsub(/^\s+/, '')
33
- { "run_list": [] }
34
- JSON
46
+ attributes = config[:first_boot_attributes] || {}
47
+ run_list = { :run_list => config[:run_list] || [] }
48
+ f.print attributes.merge(run_list).to_json
35
49
  end
36
50
  end
37
51
  end
@@ -2,7 +2,6 @@ module KnifeSolo
2
2
  module SshCommand
3
3
 
4
4
  def self.load_deps
5
- require 'knife-solo/knife_solo_error'
6
5
  require 'net/ssh'
7
6
  end
8
7
 
@@ -55,8 +54,9 @@ module KnifeSolo
55
54
 
56
55
  def validate_first_cli_arg_is_a_hostname!
57
56
  unless first_cli_arg_is_a_hostname?
58
- ui.msg opt_parser.help
59
- raise KnifeSoloError.new "need to pass atleast a [user@]hostname as the first argument"
57
+ show_usage
58
+ ui.fatal "You must specify [<user>@]<hostname> as the first argument"
59
+ exit 1
60
60
  end
61
61
  end
62
62
 
@@ -0,0 +1,90 @@
1
+ require 'test_helper'
2
+
3
+ require 'knife-solo/bootstraps'
4
+
5
+ class KnifeSolo::Bootstraps::StubOS < KnifeSolo::Bootstraps::Base
6
+ end
7
+
8
+ class KnifeSolo::Bootstraps::StubOS2 < KnifeSolo::Bootstraps::Base
9
+ def gem_packages ; ['chef'] ; end
10
+ def distro ; {:type => 'gem', :version => 'Fanny Faker'} ; end
11
+ def gem_install
12
+ # dont' actually install anything
13
+ end
14
+ end
15
+
16
+ class BootstrapsTest < TestCase
17
+ def test_bootstrap_class_exists_for
18
+ assert_equal true, KnifeSolo::Bootstraps.class_exists_for?('Stub OS')
19
+
20
+ assert_equal false, KnifeSolo::Bootstraps.class_exists_for?('Mythical OS')
21
+ end
22
+
23
+ def test_distro_raises_if_not_implemented
24
+ bootstrap = bootstrap_instance()
25
+
26
+ assert_raises RuntimeError do
27
+ bootstrap.distro()
28
+ end
29
+ end
30
+
31
+ def test_gem_packages_raises_if_not_implemented
32
+ bootstrap = bootstrap_instance()
33
+
34
+ assert_raises RuntimeError do
35
+ bootstrap.gem_packages()
36
+ end
37
+ end
38
+
39
+ def test_bootstrap_calls_appropriate_install_method
40
+ bootstrap = KnifeSolo::Bootstraps::StubOS2.new(mock)
41
+ bootstrap.stubs(:distro).returns({:type => 'disco_gem'})
42
+
43
+ bootstrap.expects(:disco_gem_install)
44
+
45
+ bootstrap.bootstrap!
46
+ end
47
+
48
+ def test_bootstrap_calls_pre_bootstrap_checks
49
+ bootstrap = KnifeSolo::Bootstraps::StubOS2.new(mock)
50
+
51
+ bootstrap.expects(:run_pre_bootstrap_checks)
52
+
53
+ bootstrap.bootstrap!
54
+ end
55
+
56
+ def test_bootstrap_delegates_to_knife_prepare
57
+ prepare = mock('chef::knife::prepare')
58
+ bootstrap = KnifeSolo::Bootstraps::StubOS2.new(prepare)
59
+
60
+ assert prepare == bootstrap.prepare
61
+ end
62
+
63
+ def test_darwin_checks_for_xcode_install_and_barfs_if_missing
64
+ bootstrap = KnifeSolo::Bootstraps::Darwin.new(mock)
65
+ # don't want to actually run anything
66
+ bootstrap.stubs(:gem_install)
67
+
68
+ bootstrap.expects(:has_xcode_installed?).returns(false)
69
+
70
+ assert_raises RuntimeError do
71
+ bootstrap.bootstrap!
72
+ end
73
+ end
74
+
75
+ def test_omnibus_install_methdod
76
+ bootstrap = KnifeSolo::Bootstraps::StubOS2.new(mock)
77
+ bootstrap.stubs(:distro).returns({:type => "omnibus"})
78
+
79
+ bootstrap.expects(:omnibus_install)
80
+
81
+ bootstrap.bootstrap!
82
+ end
83
+
84
+ # ***
85
+
86
+ def bootstrap_instance
87
+ @prepare = mock('Knife::Chef::SoloPrepare')
88
+ KnifeSolo::Bootstraps::StubOS.new(@prepare)
89
+ end
90
+ end
@@ -0,0 +1,46 @@
1
+ require 'test_helper'
2
+
3
+ require 'chef/knife'
4
+ require 'knife-solo/deprecated_command'
5
+
6
+ class DummyNewCommand < Chef::Knife
7
+ banner "knife dummy_new_command"
8
+
9
+ def run
10
+ # calls #new_run so we can be sure this gets called
11
+ new_run
12
+ end
13
+
14
+ def new_run
15
+ # dummy
16
+ end
17
+ end
18
+
19
+ class DummyDeprecatedCommand < DummyNewCommand
20
+ include KnifeSolo::DeprecatedCommand
21
+ end
22
+
23
+ class DeprecatedCommandTest < TestCase
24
+ def test_help_warns_about_deprecation
25
+ $stdout.expects(:puts).with(regexp_matches(/deprecated!/))
26
+ assert_exits { command("--help") }
27
+ end
28
+
29
+ def test_warns_about_deprecation
30
+ cmd = command
31
+ cmd.ui.expects(:err).with(regexp_matches(/deprecated!/))
32
+ cmd.run
33
+ end
34
+
35
+ def test_runs_original_command
36
+ cmd = command
37
+ cmd.ui.stubs(:err)
38
+ cmd.expects(:new_run)
39
+ cmd.run
40
+ end
41
+
42
+ def command(*args)
43
+ DummyDeprecatedCommand.load_deps
44
+ DummyDeprecatedCommand.new(args)
45
+ end
46
+ end
@@ -0,0 +1,15 @@
1
+ # Tries to bootstrap with apache2 cookbook and
2
+ # verifies the "It Works!" page is present.
3
+
4
+ require $base_dir.join('integration', 'cases', 'apache2_cook')
5
+
6
+ module Apache2Bootstrap
7
+ include Apache2Cook
8
+
9
+ def test_apache2
10
+ write_cheffile
11
+ system "librarian-chef install >> #{log_file}"
12
+ assert_subcommand "bootstrap --run-list=recipe[apache2]"
13
+ assert_match default_apache_message, http_response
14
+ end
15
+ end
@@ -0,0 +1,28 @@
1
+ # Tries to cook with apache2 cookbook and
2
+ # verifies the "It Works!" page is present.
3
+ module Apache2Cook
4
+ def write_cheffile
5
+ File.open('Cheffile', 'w') do |f|
6
+ f.print <<-CHEF
7
+ site 'http://community.opscode.com/api/v1'
8
+ cookbook 'apache2'
9
+ CHEF
10
+ end
11
+ end
12
+
13
+ def http_response
14
+ Net::HTTP.get(URI.parse("http://"+server.public_ip_address))
15
+ end
16
+
17
+ def default_apache_message
18
+ /It works!/
19
+ end
20
+
21
+ def test_apache2
22
+ write_cheffile
23
+ system "librarian-chef install >> #{log_file}"
24
+ write_nodefile(run_list: ["recipe[apache2]"])
25
+ assert_subcommand "cook"
26
+ assert_match default_apache_message, http_response
27
+ end
28
+ end
@@ -0,0 +1,8 @@
1
+ # Tries to run cook on the box
2
+ module EmptyCook
3
+ def test_empty_cook
4
+ write_nodefile(run_list: [])
5
+ assert_subcommand "cook"
6
+ end
7
+ end
8
+
@@ -0,0 +1,27 @@
1
+ require 'chef/encrypted_data_bag_item'
2
+
3
+ module EncryptedDataBag
4
+ def setup
5
+ super
6
+ FileUtils.cp $base_dir.join('support', 'data_bag_key'), 'data_bag_key'
7
+ FileUtils.cp_r $base_dir.join('support', 'secret_cookbook'), 'cookbooks/secret_cookbook'
8
+ @password = "essential particles busy loud"
9
+ create_data_bag
10
+ end
11
+
12
+ def create_data_bag
13
+ secret = Chef::EncryptedDataBagItem.load_secret('data_bag_key')
14
+ data = {"id" => "passwords", "admin" => @password}
15
+ encrypted_data = Chef::EncryptedDataBagItem.encrypt_data_bag_item(data, secret)
16
+ write_json_file('data_bags/dev/passwords.json', encrypted_data)
17
+ end
18
+
19
+ # Test that we can read an encrypted data bag value
20
+ # NOTE: This shells out to ssh, so may not be windows-compatible
21
+ def test_reading_encrypted_data_bag
22
+ write_nodefile(run_list: ["recipe[secret_cookbook]"])
23
+ assert_subcommand "cook"
24
+ actual = `ssh #{connection_string} cat /etc/admin_password`
25
+ assert_equal @password, actual
26
+ end
27
+ end
@@ -0,0 +1,19 @@
1
+ require 'integration_helper'
2
+
3
+ class Centos5_6Test < IntegrationTest
4
+ def user
5
+ "root"
6
+ end
7
+
8
+ def image_id
9
+ "ami-3fe42456"
10
+ end
11
+
12
+ def default_apache_message
13
+ /Apache 2 Test Page/
14
+ end
15
+
16
+ include EmptyCook
17
+ include Apache2Cook
18
+ include EncryptedDataBag
19
+ end
@@ -0,0 +1,18 @@
1
+ require 'integration_helper'
2
+
3
+ class Gentoo2011Test < IntegrationTest
4
+ def user
5
+ "root"
6
+ end
7
+
8
+ def image_id
9
+ "ami-ae49b7c7"
10
+ end
11
+
12
+ # `emerge chef` takes a very long time (~ 50 minutes) on an m1.small
13
+ # Uncoment this if you need to verify Gentoo operation
14
+
15
+ # include EmptyCook
16
+ # include Apache2Cook
17
+ # include EncryptedDataBag
18
+ end