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.
- data/.gitignore +8 -35
- data/.rspec +1 -0
- data/.rvmrc.template +2 -0
- data/.travis.yml +22 -0
- data/Gemfile +2 -15
- data/LICENSE +202 -201
- data/NOTICE +9 -0
- data/README.md +696 -92
- data/Rakefile +39 -25
- data/TODO.md +28 -0
- data/bin/cc-knife +32 -0
- data/bin/cucumber-chef +409 -79
- data/chef_repo/cookbooks/cucumber-chef/LICENSE +202 -0
- data/chef_repo/cookbooks/cucumber-chef/README.md +69 -0
- data/chef_repo/cookbooks/cucumber-chef/attributes/default.rb +27 -0
- data/chef_repo/cookbooks/cucumber-chef/metadata.rb +13 -0
- data/chef_repo/cookbooks/cucumber-chef/recipes/default.rb +23 -0
- data/chef_repo/cookbooks/cucumber-chef/recipes/lxc.rb +315 -0
- data/chef_repo/cookbooks/cucumber-chef/recipes/test_lab.rb +146 -0
- data/chef_repo/cookbooks/cucumber-chef/templates/default/db-168-192.erb +15 -0
- data/chef_repo/cookbooks/cucumber-chef/templates/default/db-test-lab.erb +15 -0
- data/chef_repo/cookbooks/cucumber-chef/templates/default/dhcpd-conf.erb +44 -0
- data/chef_repo/cookbooks/cucumber-chef/templates/default/gemrc.erb +10 -0
- data/{cookbooks/cucumber-chef/files/default/cucumber-net → chef_repo/cookbooks/cucumber-chef/templates/default/lxc-initializer-config.erb} +1 -1
- data/chef_repo/cookbooks/cucumber-chef/templates/default/lxc-install-chef.erb +3 -0
- data/chef_repo/cookbooks/cucumber-chef/templates/default/motd.erb +10 -0
- data/chef_repo/cookbooks/cucumber-chef/templates/default/named-conf-local.erb +25 -0
- data/{cookbooks/cucumber-chef/files/default/permissive-ssh-config → chef_repo/cookbooks/cucumber-chef/templates/default/ssh-config.erb} +3 -1
- data/chef_repo/roles/test_lab.rb +24 -0
- data/cucumber-chef.gemspec +50 -123
- data/examples/README.md +7 -0
- data/examples/users_add.feature +51 -0
- data/examples/users_auto_remove.feature +50 -0
- data/features/support/env.rb +3 -2
- data/lib/cucumber/chef/bootstrap.rb +94 -0
- data/lib/cucumber/chef/command.rb +78 -0
- data/lib/cucumber/chef/config.rb +143 -93
- data/lib/cucumber/chef/helpers/chef_client.rb +87 -0
- data/lib/cucumber/chef/helpers/chef_server.rb +90 -0
- data/lib/cucumber/chef/helpers/command.rb +57 -0
- data/lib/cucumber/chef/helpers/container.rb +154 -0
- data/lib/cucumber/chef/helpers/minitest.rb +35 -0
- data/lib/cucumber/chef/helpers/server.rb +81 -0
- data/lib/cucumber/chef/helpers/test_lab.rb +46 -0
- data/lib/cucumber/chef/helpers/utility.rb +73 -0
- data/lib/cucumber/chef/helpers.rb +56 -0
- data/lib/cucumber/chef/logger.rb +90 -0
- data/lib/cucumber/chef/provisioner.rb +275 -69
- data/lib/cucumber/chef/ssh.rb +190 -0
- data/lib/cucumber/chef/steps/chef_steps.rb +32 -0
- data/lib/cucumber/chef/steps/minitest_steps.rb +29 -0
- data/lib/cucumber/chef/steps/provision_steps.rb +60 -0
- data/lib/cucumber/chef/steps/ssh_steps.rb +95 -0
- data/lib/cucumber/chef/steps.rb +27 -0
- data/lib/cucumber/chef/tcp_socket.rb +83 -0
- data/lib/cucumber/chef/template.rb +57 -0
- data/lib/cucumber/chef/templates/bootstrap/ubuntu-precise-test-lab.erb +99 -0
- data/lib/cucumber/chef/templates/cucumber/env.rb +56 -0
- data/lib/cucumber/chef/templates/cucumber/example_feature.erb +49 -0
- data/lib/cucumber/chef/templates/cucumber/example_steps.erb +11 -0
- data/lib/cucumber/chef/templates/cucumber/readme-data_bags.erb +1 -0
- data/lib/cucumber/chef/templates/cucumber/readme-keys.erb +1 -0
- data/lib/cucumber/chef/templates/cucumber/readme-roles.erb +1 -0
- data/lib/cucumber/chef/templates/cucumber/readme.erb +18 -0
- data/lib/cucumber/chef/templates/cucumber-chef/config-rb.erb +33 -0
- data/lib/cucumber/chef/templates/cucumber-chef/cucumber-yml.erb +2 -0
- data/lib/cucumber/chef/templates/cucumber-chef/knife-rb.erb +18 -0
- data/lib/cucumber/chef/test_lab.rb +308 -52
- data/lib/cucumber/chef/test_runner.rb +86 -15
- data/lib/cucumber/chef/utility.rb +128 -0
- data/lib/cucumber/chef/version.rb +30 -1
- data/lib/cucumber/chef.rb +53 -20
- data/lib/cucumber-chef.rb +24 -1
- data/spec/cucumber/chef/config_spec.rb +144 -78
- data/spec/cucumber/chef/provisioner_spec.rb +60 -16
- data/spec/cucumber/chef/test_lab_spec.rb +62 -19
- data/spec/spec_helper.rb +30 -26
- data/todo.org +17 -0
- metadata +267 -163
- data/.document +0 -5
- data/VERSION +0 -1
- data/cookbooks/cucumber-chef/README.rdoc +0 -8
- data/cookbooks/cucumber-chef/files/default/add-git-identity +0 -2
- data/cookbooks/cucumber-chef/files/default/controller-first-boot +0 -1
- data/cookbooks/cucumber-chef/files/default/cucumber-private-key +0 -27
- data/cookbooks/cucumber-chef/files/default/cucumber-run_list +0 -1
- data/cookbooks/cucumber-chef/files/default/git-private-key +0 -27
- data/cookbooks/cucumber-chef/files/default/install-chef +0 -1
- data/cookbooks/cucumber-chef/files/default/lxc-controller-network-config +0 -5
- data/cookbooks/cucumber-chef/files/default/lxc-lucid-chef +0 -378
- data/cookbooks/cucumber-chef/metadata.rb +0 -6
- data/cookbooks/cucumber-chef/recipes/controller.rb +0 -51
- data/cookbooks/cucumber-chef/recipes/lxc.rb +0 -35
- data/cookbooks/cucumber-chef/recipes/test_lab.rb +0 -23
- data/cookbooks/cucumber-chef/recipes/testrunner.rb +0 -46
- data/cookbooks/cucumber-chef/roles/controller.rb +0 -7
- data/cookbooks/cucumber-chef/roles/test_lab_test.rb +0 -9
- data/cookbooks/cucumber-chef/templates/default/controller-client.erb +0 -5
- data/cookbooks/cucumber-chef/templates/default/lxc-lucid-chef +0 -385
- data/lib/cucumber/chef/handy.rb +0 -90
- data/lib/cucumber/chef/templates/controller.erb +0 -35
- data/lib/cucumber/chef/templates/env.rb +0 -16
- data/lib/cucumber/chef/templates/example_feature.erb +0 -11
- data/lib/cucumber/chef/templates/example_step.erb +0 -19
- data/lib/cucumber/chef/templates/readme.erb +0 -14
- data/lib/cucumber/chef/templates/ubuntu10.04-gems.erb +0 -43
- data/lib/cucumber/ec2_server_create.rb +0 -99
- 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,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 -%>
|