cucumber-chef 1.0.3 → 2.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. data/.gitignore +8 -35
  2. data/.rspec +1 -0
  3. data/.rvmrc.template +2 -0
  4. data/.travis.yml +22 -0
  5. data/Gemfile +2 -15
  6. data/LICENSE +202 -201
  7. data/NOTICE +9 -0
  8. data/README.md +696 -92
  9. data/Rakefile +39 -25
  10. data/TODO.md +28 -0
  11. data/bin/cc-knife +32 -0
  12. data/bin/cucumber-chef +409 -79
  13. data/chef_repo/cookbooks/cucumber-chef/LICENSE +202 -0
  14. data/chef_repo/cookbooks/cucumber-chef/README.md +69 -0
  15. data/chef_repo/cookbooks/cucumber-chef/attributes/default.rb +27 -0
  16. data/chef_repo/cookbooks/cucumber-chef/metadata.rb +13 -0
  17. data/chef_repo/cookbooks/cucumber-chef/recipes/default.rb +23 -0
  18. data/chef_repo/cookbooks/cucumber-chef/recipes/lxc.rb +315 -0
  19. data/chef_repo/cookbooks/cucumber-chef/recipes/test_lab.rb +146 -0
  20. data/chef_repo/cookbooks/cucumber-chef/templates/default/db-168-192.erb +15 -0
  21. data/chef_repo/cookbooks/cucumber-chef/templates/default/db-test-lab.erb +15 -0
  22. data/chef_repo/cookbooks/cucumber-chef/templates/default/dhcpd-conf.erb +44 -0
  23. data/chef_repo/cookbooks/cucumber-chef/templates/default/gemrc.erb +10 -0
  24. data/{cookbooks/cucumber-chef/files/default/cucumber-net → chef_repo/cookbooks/cucumber-chef/templates/default/lxc-initializer-config.erb} +1 -1
  25. data/chef_repo/cookbooks/cucumber-chef/templates/default/lxc-install-chef.erb +3 -0
  26. data/chef_repo/cookbooks/cucumber-chef/templates/default/motd.erb +10 -0
  27. data/chef_repo/cookbooks/cucumber-chef/templates/default/named-conf-local.erb +25 -0
  28. data/{cookbooks/cucumber-chef/files/default/permissive-ssh-config → chef_repo/cookbooks/cucumber-chef/templates/default/ssh-config.erb} +3 -1
  29. data/chef_repo/roles/test_lab.rb +24 -0
  30. data/cucumber-chef.gemspec +50 -123
  31. data/examples/README.md +7 -0
  32. data/examples/users_add.feature +51 -0
  33. data/examples/users_auto_remove.feature +50 -0
  34. data/features/support/env.rb +3 -2
  35. data/lib/cucumber/chef/bootstrap.rb +94 -0
  36. data/lib/cucumber/chef/command.rb +78 -0
  37. data/lib/cucumber/chef/config.rb +143 -93
  38. data/lib/cucumber/chef/helpers/chef_client.rb +87 -0
  39. data/lib/cucumber/chef/helpers/chef_server.rb +90 -0
  40. data/lib/cucumber/chef/helpers/command.rb +57 -0
  41. data/lib/cucumber/chef/helpers/container.rb +154 -0
  42. data/lib/cucumber/chef/helpers/minitest.rb +35 -0
  43. data/lib/cucumber/chef/helpers/server.rb +81 -0
  44. data/lib/cucumber/chef/helpers/test_lab.rb +46 -0
  45. data/lib/cucumber/chef/helpers/utility.rb +73 -0
  46. data/lib/cucumber/chef/helpers.rb +56 -0
  47. data/lib/cucumber/chef/logger.rb +90 -0
  48. data/lib/cucumber/chef/provisioner.rb +275 -69
  49. data/lib/cucumber/chef/ssh.rb +190 -0
  50. data/lib/cucumber/chef/steps/chef_steps.rb +32 -0
  51. data/lib/cucumber/chef/steps/minitest_steps.rb +29 -0
  52. data/lib/cucumber/chef/steps/provision_steps.rb +60 -0
  53. data/lib/cucumber/chef/steps/ssh_steps.rb +95 -0
  54. data/lib/cucumber/chef/steps.rb +27 -0
  55. data/lib/cucumber/chef/tcp_socket.rb +83 -0
  56. data/lib/cucumber/chef/template.rb +57 -0
  57. data/lib/cucumber/chef/templates/bootstrap/ubuntu-precise-test-lab.erb +99 -0
  58. data/lib/cucumber/chef/templates/cucumber/env.rb +56 -0
  59. data/lib/cucumber/chef/templates/cucumber/example_feature.erb +49 -0
  60. data/lib/cucumber/chef/templates/cucumber/example_steps.erb +11 -0
  61. data/lib/cucumber/chef/templates/cucumber/readme-data_bags.erb +1 -0
  62. data/lib/cucumber/chef/templates/cucumber/readme-keys.erb +1 -0
  63. data/lib/cucumber/chef/templates/cucumber/readme-roles.erb +1 -0
  64. data/lib/cucumber/chef/templates/cucumber/readme.erb +18 -0
  65. data/lib/cucumber/chef/templates/cucumber-chef/config-rb.erb +33 -0
  66. data/lib/cucumber/chef/templates/cucumber-chef/cucumber-yml.erb +2 -0
  67. data/lib/cucumber/chef/templates/cucumber-chef/knife-rb.erb +18 -0
  68. data/lib/cucumber/chef/test_lab.rb +308 -52
  69. data/lib/cucumber/chef/test_runner.rb +86 -15
  70. data/lib/cucumber/chef/utility.rb +128 -0
  71. data/lib/cucumber/chef/version.rb +30 -1
  72. data/lib/cucumber/chef.rb +53 -20
  73. data/lib/cucumber-chef.rb +24 -1
  74. data/spec/cucumber/chef/config_spec.rb +144 -78
  75. data/spec/cucumber/chef/provisioner_spec.rb +60 -16
  76. data/spec/cucumber/chef/test_lab_spec.rb +62 -19
  77. data/spec/spec_helper.rb +30 -26
  78. data/todo.org +17 -0
  79. metadata +267 -163
  80. data/.document +0 -5
  81. data/VERSION +0 -1
  82. data/cookbooks/cucumber-chef/README.rdoc +0 -8
  83. data/cookbooks/cucumber-chef/files/default/add-git-identity +0 -2
  84. data/cookbooks/cucumber-chef/files/default/controller-first-boot +0 -1
  85. data/cookbooks/cucumber-chef/files/default/cucumber-private-key +0 -27
  86. data/cookbooks/cucumber-chef/files/default/cucumber-run_list +0 -1
  87. data/cookbooks/cucumber-chef/files/default/git-private-key +0 -27
  88. data/cookbooks/cucumber-chef/files/default/install-chef +0 -1
  89. data/cookbooks/cucumber-chef/files/default/lxc-controller-network-config +0 -5
  90. data/cookbooks/cucumber-chef/files/default/lxc-lucid-chef +0 -378
  91. data/cookbooks/cucumber-chef/metadata.rb +0 -6
  92. data/cookbooks/cucumber-chef/recipes/controller.rb +0 -51
  93. data/cookbooks/cucumber-chef/recipes/lxc.rb +0 -35
  94. data/cookbooks/cucumber-chef/recipes/test_lab.rb +0 -23
  95. data/cookbooks/cucumber-chef/recipes/testrunner.rb +0 -46
  96. data/cookbooks/cucumber-chef/roles/controller.rb +0 -7
  97. data/cookbooks/cucumber-chef/roles/test_lab_test.rb +0 -9
  98. data/cookbooks/cucumber-chef/templates/default/controller-client.erb +0 -5
  99. data/cookbooks/cucumber-chef/templates/default/lxc-lucid-chef +0 -385
  100. data/lib/cucumber/chef/handy.rb +0 -90
  101. data/lib/cucumber/chef/templates/controller.erb +0 -35
  102. data/lib/cucumber/chef/templates/env.rb +0 -16
  103. data/lib/cucumber/chef/templates/example_feature.erb +0 -11
  104. data/lib/cucumber/chef/templates/example_step.erb +0 -19
  105. data/lib/cucumber/chef/templates/readme.erb +0 -14
  106. data/lib/cucumber/chef/templates/ubuntu10.04-gems.erb +0 -43
  107. data/lib/cucumber/ec2_server_create.rb +0 -99
  108. data/website/website.html +0 -385
@@ -0,0 +1,60 @@
1
+ ################################################################################
2
+ #
3
+ # Author: Stephen Nelson-Smith <stephen@atalanta-systems.com>
4
+ # Author: Zachary Patten <zachary@jovelabs.com>
5
+ # Copyright: Copyright (c) 2011-2012 Atalanta Systems Ltd
6
+ # License: Apache License, Version 2.0
7
+ #
8
+ # Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing, software
15
+ # distributed under the License is distributed on an "AS IS" BASIS,
16
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ # See the License for the specific language governing permissions and
18
+ # limitations under the License.
19
+ #
20
+ ################################################################################
21
+
22
+ Given /^I have a server called "([^\"]*)"$/ do |name|
23
+ @servers = (@servers || Hash.new(nil)).merge(name => Hash.new(nil))
24
+ end
25
+
26
+ And /^"([^\"]*)" is running "([^\"]*)" "([^\"]*)"$/ do |name, distro, release|
27
+ @servers[name].merge!( :distro => distro, :release => release )
28
+ end
29
+
30
+ And /^"([^\"]*)" has "([^\"]*)" architecture$/ do |name, arch|
31
+ @servers[name].merge!( :arch => arch )
32
+ end
33
+
34
+ And /^"([^\"]*)" should( not)? be persistant$/ do |name, boolean|
35
+ @servers[name].merge!( :persist => (!boolean ? true : false) )
36
+ end
37
+
38
+ And /^"([^\"]*)" has an IP address of "([^\"]*)"$/ do |name, ip|
39
+ @servers[name].merge!( :ip => ip )
40
+ end
41
+
42
+ And /^"([^\"]*)" has a MAC address of "([^\"]*)"$/ do |name, mac|
43
+ @servers[name].merge!( :mac => ip )
44
+ end
45
+
46
+ And /^"([^\"]*)" has been provisioned$/ do |name|
47
+ server_create(name, @servers[name])
48
+ end
49
+
50
+ And /^the "([^\"]*)" role has been added to the "([^\"]*)" run list$/ do |role, name|
51
+ chef_set_client_attributes(@servers[name], :run_list => ["role[#{role}]"])
52
+ end
53
+
54
+ And /^the "([^\"]*)" recipe has been added to the "([^\"]*)" run list$/ do |recipe, name|
55
+ chef_set_client_attributes(@servers[name], :run_list => ["recipe[#{recipe}]"])
56
+ end
57
+
58
+ And /^the chef-client has been run on "([^\"]*)"$/ do |name|
59
+ chef_run_client(name)
60
+ end
@@ -0,0 +1,95 @@
1
+ Given /^I have no public keys set$/ do
2
+ @auth_methods = %w(password)
3
+ end
4
+
5
+ Then /^I can ssh to "([^\"]*)" with the following credentials:$/ do |hostname, table|
6
+ @auth_methods ||= %w(publickey password)
7
+
8
+ credentials = table.hashes
9
+ credentials.each do |creds|
10
+ lambda {
11
+ Net::SSH.start(session["hostname"], creds["username"], :password => creds["password"], :auth_methods => @auth_methods)
12
+ }.should_not raise_error(Net::SSH::AuthenticationFailed)
13
+ end
14
+ end
15
+
16
+ Then /^I can ssh to the following hosts with these credentials:$/ do |table|
17
+ @keys ||= []
18
+ @auth_methods ||= %w(password)
19
+ session_details = table.hashes
20
+
21
+ session_details.each do |session|
22
+ # initialize a list of keys and auth methods for just this session, as
23
+ # session can have session-specific keys mixed with global keys
24
+ session_keys = Array.new(@keys)
25
+ session_auth_methods = Array.new(@auth_methods)
26
+
27
+ # you can pass in a keyfile in the session details, so we need to
28
+ if session["keyfile"]
29
+ session_keys << session["keyfile"]
30
+ session_auth_methods << "publickey"
31
+ end
32
+
33
+ lambda {
34
+ @connection = Net::SSH.start(session["hostname"],
35
+ session["username"],
36
+ :password => session["password"],
37
+ :auth_methods => session_auth_methods,
38
+ :keys => session_keys)
39
+ }.should_not raise_error
40
+ end
41
+ end
42
+
43
+ Given /^I have the following public keys:$/ do |table|
44
+ @keys = []
45
+ public_key_paths = table.hashes
46
+
47
+ public_key_paths.each do |key|
48
+ File.exist?(key["keyfile"]).should be_true
49
+ FileUtils.chmod(0600, key["keyfile"])
50
+ @keys << key["keyfile"]
51
+ end
52
+
53
+ @auth_methods ||= %w(password)
54
+ @auth_methods << "publickey"
55
+ end
56
+
57
+ When /^I ssh to "([^\"]*)" with the following credentials:$/ do |hostname, table|
58
+ @keys = []
59
+ @auth_methods ||= %w(password)
60
+ session = table.hashes.first
61
+ session_keys = Array.new(@keys)
62
+ session_auth_methods = Array.new(@auth_methods)
63
+ if session["keyfile"]
64
+ session_keys << session["keyfile"]
65
+ session_auth_methods << "publickey"
66
+ end
67
+
68
+ lambda {
69
+ @connection = Net::SSH.start(hostname,
70
+ session["username"],
71
+ :password => session["password"],
72
+ :auth_methods => session_auth_methods,
73
+ :keys => session_keys)
74
+ }.should_not raise_error
75
+ end
76
+
77
+ And /^I run "([^\"]*)"$/ do |command|
78
+ @output = @connection.exec!(command)
79
+ end
80
+
81
+ Then /^I should( not)? see "([^\"]*)" in the output$/ do |boolean, string|
82
+ if (!boolean)
83
+ @output.should =~ /#{string}/
84
+ else
85
+ @output.should_not =~ /#{string}/
86
+ end
87
+ end
88
+
89
+ Then /^I should( not)? see the "([^\"]*)" of "([^\"]*)" in the output$/ do |boolean, key, name|
90
+ if (!boolean)
91
+ @output.should =~ /#{$servers[name][key.downcase.to_sym]}/i
92
+ else
93
+ @output.should_not =~ /#{$servers[name][key.downcase.to_sym]}/i
94
+ end
95
+ end
@@ -0,0 +1,27 @@
1
+ ################################################################################
2
+ #
3
+ # Author: Stephen Nelson-Smith <stephen@atalanta-systems.com>
4
+ # Author: Zachary Patten <zachary@jovelabs.com>
5
+ # Copyright: Copyright (c) 2011-2012 Atalanta Systems Ltd
6
+ # License: Apache License, Version 2.0
7
+ #
8
+ # Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing, software
15
+ # distributed under the License is distributed on an "AS IS" BASIS,
16
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ # See the License for the specific language governing permissions and
18
+ # limitations under the License.
19
+ #
20
+ ################################################################################
21
+
22
+ require 'cucumber/chef/steps/chef_steps'
23
+ require 'cucumber/chef/steps/minitest_steps'
24
+ require 'cucumber/chef/steps/provision_steps'
25
+ require 'cucumber/chef/steps/ssh_steps'
26
+
27
+ ################################################################################
@@ -0,0 +1,83 @@
1
+ ################################################################################
2
+ #
3
+ # Author: Stephen Nelson-Smith <stephen@atalanta-systems.com>
4
+ # Author: Zachary Patten <zachary@jovelabs.com>
5
+ # Copyright: Copyright (c) 2011-2012 Atalanta Systems Ltd
6
+ # License: Apache License, Version 2.0
7
+ #
8
+ # Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing, software
15
+ # distributed under the License is distributed on an "AS IS" BASIS,
16
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ # See the License for the specific language governing permissions and
18
+ # limitations under the License.
19
+ #
20
+ ################################################################################
21
+
22
+ module Cucumber
23
+ module Chef
24
+
25
+ class TCPSocketError < Error; end
26
+
27
+ class TCPSocket
28
+
29
+ ################################################################################
30
+
31
+ def initialize(host, port, data=nil)
32
+ @host, @port, @data = host, port, data
33
+
34
+ if !host
35
+ message = "You must supply a host!"
36
+ $logger.fatal { message } if $logger
37
+ raise TCPSocketError, message
38
+ end
39
+
40
+ if !port
41
+ message = "You must supply a port!"
42
+ $logger.fatal { message } if $logger
43
+ raise TCPSocketError, message
44
+ end
45
+ end
46
+
47
+ ################################################################################
48
+
49
+ def ready?
50
+ socket = ::TCPSocket.new(@host, @port)
51
+
52
+ if @data.nil?
53
+ $logger.debug { "read(#{@host}:#{@port})" } if $logger
54
+ ((::IO.select([socket], nil, nil, 5) && socket.gets) ? true : false)
55
+ else
56
+ $logger.debug { "write(#{@host}:#{@port}, '#{@data}')" } if $logger
57
+ ((::IO.select(nil, [socket], nil, 5) && socket.write(@data)) ? true : false)
58
+ end
59
+
60
+ rescue Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::EHOSTUNREACH => e
61
+ $logger.debug { "#{@host}:#{@port} - #{e.message}" } if $logger
62
+ false
63
+ ensure
64
+ (socket && socket.close)
65
+ end
66
+
67
+ ################################################################################
68
+
69
+ def wait
70
+ begin
71
+ success = ready?
72
+ sleep(1)
73
+ end until success
74
+ end
75
+
76
+ ################################################################################
77
+
78
+ end
79
+
80
+ end
81
+ end
82
+
83
+ ################################################################################
@@ -0,0 +1,57 @@
1
+ ################################################################################
2
+ #
3
+ # Author: Stephen Nelson-Smith <stephen@atalanta-systems.com>
4
+ # Author: Zachary Patten <zachary@jovelabs.com>
5
+ # Copyright: Copyright (c) 2011-2012 Atalanta Systems Ltd
6
+ # License: Apache License, Version 2.0
7
+ #
8
+ # Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing, software
15
+ # distributed under the License is distributed on an "AS IS" BASIS,
16
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ # See the License for the specific language governing permissions and
18
+ # limitations under the License.
19
+ #
20
+ ################################################################################
21
+
22
+ module Cucumber
23
+ module Chef
24
+
25
+ class TemplateError < Error; end
26
+
27
+ class Template
28
+
29
+ ################################################################################
30
+
31
+ def self.render(template, context=nil)
32
+ self.render_template(self.load_template(template), context)
33
+ end
34
+
35
+
36
+ ################################################################################
37
+ private
38
+ ################################################################################
39
+
40
+ def self.load_template(template)
41
+ IO.read(template).chomp
42
+ end
43
+
44
+ ################################################################################
45
+
46
+ def self.render_template(template, context)
47
+ Erubis::Eruby.new(template).evaluate(:config => context)
48
+ end
49
+
50
+ ################################################################################
51
+
52
+ end
53
+
54
+ end
55
+ end
56
+
57
+ ################################################################################
@@ -0,0 +1,99 @@
1
+ bash -c '
2
+ CUCUMBER_CHEF_BOOTSTRAP_DONE="/.cucumber-chef-bootstrap-finished"
3
+ [ -f ${CUCUMBER_CHEF_BOOTSTRAP_DONE} ] && echo "Already bootstrapped!" && exit
4
+
5
+ export DEBIAN_FRONTEND=noninteractive
6
+
7
+ sed -i "s/127.0.0.1 localhost/127.0.0.1 <%= @config[:hostname] %> <%= @config[:hostname].split(".")[0] %> localhost/" /etc/hosts
8
+ echo "<%= @config[:hostname] %>" | tee /etc/hostname
9
+ hostname <%= @config[:hostname] %>
10
+
11
+ echo "deb http://apt.opscode.com/ `lsb_release -cs`-0.10 main" | tee /etc/apt/sources.list.d/opscode.list
12
+ mkdir -p /etc/apt/trusted.gpg.d
13
+ gpg --fetch-key http://apt.opscode.com/packages@opscode.com.gpg.key
14
+ gpg --export packages@opscode.com | tee /etc/apt/trusted.gpg.d/opscode-keyring.gpg > /dev/null
15
+ apt-get -q -y --force-yes update
16
+ apt-get -q -y --force-yes -o Dpkg::Options::="--force-confnew" install opscode-keyring
17
+ chown -R ${SUDO_USER}:${SUDO_USER} ${HOME}/.gnupg
18
+ apt-get -q -y upgrade
19
+
20
+ cat <<EOF | debconf-set-selections
21
+ chef chef/chef_server_url string http://<%= @config[:chef_server] %>:4000
22
+ chef-solr chef-solr/amqp_password password <%= @config[:amqp_password] %>
23
+ chef-server-webui chef-server-webui/admin_password password <%= @config[:admin_password] %>
24
+ EOF
25
+
26
+ apt-get -q -y install chef chef-server
27
+
28
+ echo -n "Waiting on validation.pem and webui.pem to appear..."
29
+ until [ -f /etc/chef/validation.pem ] && [ -f /etc/chef/webui.pem ]; do
30
+ echo -n "."
31
+ sleep 1
32
+ done
33
+ echo "done."
34
+
35
+ mkdir -p ~/.chef
36
+ cp /etc/chef/validation.pem /etc/chef/webui.pem ~/.chef
37
+
38
+ apt-get -q -y install expect
39
+ KNIFE_CONFIG_EXP_FILE="/tmp/knife-config.exp"
40
+ cat <<EOF > ${KNIFE_CONFIG_EXP_FILE}
41
+ #!/usr/bin/expect -f
42
+ set timeout 10
43
+ spawn knife configure -i
44
+ expect "Overwrite ${HOME}/.chef/knife.rb" { send "Y\n" }
45
+ expect "Where should I put the config file?" { send "\n" }
46
+ expect "Please enter the chef server URL" { send "\n" }
47
+ expect "Please enter a clientname for the new client" { send "${SUDO_USER}\n" }
48
+ expect "Please enter the existing admin clientname" { send "\n" }
49
+ expect "Please enter the location of the existing admin client" { send "${HOME}/.chef/webui.pem\n" }
50
+ expect "Please enter the validation clientname" { send "\n" }
51
+ expect "Please enter the location of the validation key" { send "${HOME}/.chef/validation.pem\n" }
52
+ expect "Please enter the path to a chef repository" { send "${HOME}/chef_repo\n" }
53
+ interact
54
+ EOF
55
+ chmod +x ${KNIFE_CONFIG_EXP_FILE}
56
+ ${KNIFE_CONFIG_EXP_FILE}
57
+
58
+ knife client create <%= @config[:user] %> -d -a -f ${HOME}/.chef/<%= @config[:user] %>.pem
59
+
60
+ chown -R ${SUDO_USER}:${SUDO_USER} ${HOME}
61
+
62
+ nc -w 1 127.0.0.1 4040
63
+ if [ $? -ne 0 ]; then
64
+ /etc/init.d/chef-server-webui stop && sleep 3
65
+ /usr/sbin/chef-server-webui -e production &
66
+ while true; do
67
+ nc -w 1 127.0.0.1 4040
68
+ if [ $? -eq 0 ]; then
69
+ break
70
+ fi
71
+ sleep 1
72
+ done
73
+ kill `jobs -p` && sleep 3
74
+ /etc/init.d/chef-server-webui start && sleep 3
75
+ fi
76
+
77
+ if [ ! -f /etc/chef/client.pem ]; then
78
+ /etc/init.d/chef-client restart
79
+ echo -n "Waiting on client.pem to appear..."
80
+ i="0"
81
+ until [ -f /etc/chef/client.pem ]; do
82
+ i=$[$i+1]
83
+ sleep 1
84
+ echo -n "."
85
+ if [ $i -gt 60 ]; then
86
+ echo -n "restart-chef-client"
87
+ /etc/init.d/chef-client restart
88
+ i="0"
89
+ fi
90
+ done
91
+ echo "done."
92
+ fi
93
+
94
+ cat <<EOF > /etc/chef/first-boot.json
95
+ <%= @config[:attributes].to_json %>
96
+ EOF
97
+
98
+ touch ${CUCUMBER_CHEF_BOOTSTRAP_DONE}
99
+ '
@@ -0,0 +1,56 @@
1
+ require 'rspec/expectations'
2
+ require 'cucumber/chef'
3
+ require 'cucumber/chef/helpers'
4
+ require 'cucumber/chef/steps'
5
+ require 'cucumber/chef/version'
6
+
7
+ class CustomWorld
8
+ include Cucumber::Chef
9
+ include Cucumber::Chef::Helpers
10
+ end
11
+
12
+ World do
13
+ CustomWorld.new
14
+ end
15
+
16
+ $servers = Hash.new(nil)
17
+
18
+ Before do
19
+ knife_rb = Cucumber::Chef.locate(:file, ".chef", "knife.rb")
20
+ Chef::Config.from_file(knife_rb)
21
+
22
+ $servers_bin ||= (Cucumber::Chef.locate(:file, ENV['HOME'], "servers.bin") rescue File.expand_path(File.join(ENV['HOME'], "servers.bin")))
23
+
24
+ # cleanup previous lxc containers if asked
25
+ if (ENV['DESTROY'] == "1")
26
+ log("servers", "are being destroyed")
27
+ servers.each do |name|
28
+ server_destroy(name)
29
+ end
30
+ File.exists?($servers_bin) && File.delete($servers_bin)
31
+ else
32
+ log("servers", "are being preserved")
33
+ end
34
+
35
+ if File.exists?($servers_bin)
36
+ $servers = Marshal.load(IO.read($servers_bin))
37
+ end
38
+
39
+ chef_set_client_config(:chef_server_url => "http://192.168.255.254:4000",
40
+ :validation_client_name => "chef-validator")
41
+ end
42
+
43
+ After do |scenario|
44
+ @connection.close if @connection
45
+
46
+ File.open($servers_bin, 'w') do |f|
47
+ f.puts(Marshal.dump($servers))
48
+ end
49
+
50
+ Kernel.exit if scenario.failed?
51
+
52
+ # cleanup non-persistent lxc containers on exit
53
+ $servers.select{ |name, attributes| !attributes[:persist] }.each do |name, attributes|
54
+ server_destroy(name)
55
+ end
56
+ end
@@ -0,0 +1,49 @@
1
+ @<%= @project %>
2
+ Feature: Perform test driven infrastructure with Cucumber-Chef
3
+ In order to learn how to develop test driven infrastructure
4
+ As an infrastructure developer
5
+ I want to better understand how to use Cucumber-Chef
6
+
7
+ Background:
8
+ * I have a server called "<%= @project %>"
9
+ * "<%= @project %>" is running "ubuntu" "lucid"
10
+ * "<%= @project %>" has been provisioned
11
+ * the "chef-client::service" recipe has been added to the "<%= @project %>" run list
12
+ * the chef-client has been run on "<%= @project %>"
13
+ * I ssh to "<%= @project %>" with the following credentials:
14
+ | username | keyfile |
15
+ | root | ../.ssh/id_rsa |
16
+
17
+ Scenario: Can connect to the provisioned server via SSH authentication
18
+ When I run "hostname"
19
+ Then I should see "<%= @project %>" in the output
20
+
21
+ Scenario: Default root shell is bash
22
+ When I run "echo $SHELL"
23
+ Then I should see "bash" in the output
24
+
25
+ Scenario: Default gateway and resolver are using Cucumber-Chef Test Lab
26
+ When I run "route -n | grep 'UG'"
27
+ Then I should see "192.168.255.254" in the output
28
+ When I run "cat /etc/resolv.conf"
29
+ Then I should see "192.168.255.254" in the output
30
+ And I should see "8.8.8.8" in the output
31
+ And I should see "8.8.4.4" in the output
32
+
33
+ Scenario: Primary interface is configured with my IP address and MAC address
34
+ When I run "ifconfig eth0"
35
+ Then I should see the "IP" of "<%= @project %>" in the output
36
+ And I should see the "MAC" of "<%= @project %>" in the output
37
+
38
+ Scenario: Local interface is not configured with my IP address or MAC address
39
+ When I run "ifconfig lo"
40
+ Then I should see "127.0.0.1" in the output
41
+ And I should not see the "IP" of "<%= @project %>" in the output
42
+ And I should not see the "MAC" of "<%= @project %>" in the output
43
+
44
+ Scenario: Chef-Client is running as a daemon
45
+ When I run "ps aux | grep [c]hef-client"
46
+ Then I should see "chef-client" in the output
47
+ And I should see "-d" in the output
48
+ And I should see "-i 1800" in the output
49
+ And I should see "-s 20" in the output
@@ -0,0 +1,11 @@
1
+ Given /^some initial state$/ do
2
+ pending # express the regexp above with the code you wish you had
3
+ end
4
+
5
+ When /^tickle$/ do
6
+ pending # express the regexp above with the code you wish you had
7
+ end
8
+
9
+ Then /^resulting state$/ do
10
+ pending # express the regexp above with the code you wish you had
11
+ end
@@ -0,0 +1 @@
1
+ Create supporting data bags here. Each data bag should get it's own subdirectory just like normal.
@@ -0,0 +1 @@
1
+ Place supporting public key pairs here.
@@ -0,0 +1 @@
1
+ Create supporting roles here.
@@ -0,0 +1,18 @@
1
+ Welcome to the suite of cucumber-chef tests
2
+
3
+ Your general workflow will be to write cucumber features that describe the intended behaviour. You will then write failing tests by writing steps to test the behaviour, expressing them as cucumer scenarios.
4
+
5
+ You will then want to create a cookbook, and write recipes that make your tests pass. Upload your cookbook to your Hosted Chef-Server using 'knife' or the Cucumber-Chef Test Lab OS Chef-Server using the 'cc-knife' tool, and then run the tests with:
6
+
7
+ cucumber-chef test [cucumber options]
8
+
9
+ For an example feature, take a look at <chef-repo>/features/<%= @project %>/<%= @project %>.feature
10
+
11
+ For an example step definition, look at <chef-repo>/features/<%= @project %>/step_definitions/<%= @project %>_steps.rb
12
+
13
+ Cucumber-Chef Test Lab Network
14
+ ==============================
15
+ CIDR: 192.168.0.0/16
16
+ Network: 192.168.0.0
17
+ Broadcast: 192.168.255.255
18
+ Test Lab/Gateway: 192.168.255.254
@@ -0,0 +1,33 @@
1
+ ################################################################################
2
+ # Cucumber-Chef
3
+ ################################################################################
4
+
5
+ provider :aws
6
+ librarian_chef <%= @librarian_chef %>
7
+
8
+
9
+ ################################################################################
10
+ # Provider: AWS
11
+ ################################################################################
12
+
13
+ aws[:aws_access_key_id] = "<%= @aws_access_key %>"
14
+ aws[:aws_secret_access_key] = "<%= @aws_secret_access_key %>"
15
+
16
+ aws[:aws_ssh_key_id] = "<%= @aws_ssh_id %>"
17
+ aws[:identity_file] = "<%= File.join(@aws_ssh_key_dir, @aws_ssh_key) %>"
18
+
19
+ aws[:region] = "<%= @region %>-1"
20
+ aws[:availability_zone] = "<%= @region %>-1a"
21
+
22
+ #aws[:aws_instance_arch] = "i386"
23
+ #aws[:aws_instance_disk_store] = "instance-store"
24
+ #aws[:aws_instance_type] = "m1.small"
25
+
26
+ #aws[:aws_security_group] = "cucumber-chef"
27
+
28
+
29
+ ################################################################################
30
+ # Provider: Vagrant
31
+ ################################################################################
32
+
33
+ # TODO
@@ -0,0 +1,2 @@
1
+ ---
2
+ default: -c -v
@@ -0,0 +1,18 @@
1
+ current_dir = File.dirname(__FILE__)
2
+
3
+ log_level :debug
4
+ log_location STDOUT
5
+ node_name "<%= @config[:user] %>"
6
+ client_key "#{current_dir}/<%= @config[:user] %>.pem"
7
+ validation_client_name "chef-validator"
8
+ validation_key "#{current_dir}/validation.pem"
9
+ chef_server_url "http://<%= @config[:chef_server] %>:4000"
10
+ cache_type "BasicFile"
11
+ cookbook_path ['#{current_dir}/../cookbooks']
12
+
13
+ cache_options(:path => "#{current_dir}/checksums")
14
+ <% if @config[:librarian_chef] -%>
15
+
16
+ require 'librarian/chef/integration/knife'
17
+ cookbook_path Librarian::Chef.install_path, "#{current_dir}/../site-cookbooks"
18
+ <% end -%>