cucumber-chef 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +45 -0
- data/Gemfile +21 -0
- data/LICENSE +201 -0
- data/README.md +83 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/bin/cucumber-chef +162 -0
- data/cookbooks/cucumber-chef/README.rdoc +8 -0
- data/cookbooks/cucumber-chef/files/default/add-git-identity +2 -0
- data/cookbooks/cucumber-chef/files/default/controller-first-boot +1 -0
- data/cookbooks/cucumber-chef/files/default/cucumber-net +5 -0
- data/cookbooks/cucumber-chef/files/default/cucumber-private-key +27 -0
- data/cookbooks/cucumber-chef/files/default/cucumber-run_list +1 -0
- data/cookbooks/cucumber-chef/files/default/git-private-key +27 -0
- data/cookbooks/cucumber-chef/files/default/install-chef +1 -0
- data/cookbooks/cucumber-chef/files/default/lxc-controller-network-config +5 -0
- data/cookbooks/cucumber-chef/files/default/lxc-lucid-chef +377 -0
- data/cookbooks/cucumber-chef/files/default/permissive-ssh-config +3 -0
- data/cookbooks/cucumber-chef/metadata.rb +6 -0
- data/cookbooks/cucumber-chef/recipes/controller.rb +50 -0
- data/cookbooks/cucumber-chef/recipes/lxc.rb +35 -0
- data/cookbooks/cucumber-chef/recipes/test_lab.rb +23 -0
- data/cookbooks/cucumber-chef/recipes/testrunner.rb +46 -0
- data/cookbooks/cucumber-chef/roles/controller.rb +7 -0
- data/cookbooks/cucumber-chef/roles/test_lab_test.rb +9 -0
- data/cookbooks/cucumber-chef/templates/default/controller-client.erb +5 -0
- data/cookbooks/cucumber-chef/templates/default/lxc-lucid-chef +385 -0
- data/cucumber-chef.gemspec +118 -0
- data/features/installing.feature +10 -0
- data/features/steps/installing_steps.rb +34 -0
- data/features/steps/setup_steps.rb +32 -0
- data/features/steps/upload_steps.rb +11 -0
- data/features/steps/usage_steps.rb +62 -0
- data/features/support/env.rb +25 -0
- data/features/support/filetools.rb +9 -0
- data/features/support/silent_system.rb +4 -0
- data/features/usage.feature +26 -0
- data/lib/cucumber-chef.rb +1 -0
- data/lib/cucumber/chef.rb +195 -0
- data/lib/cucumber/chef/handy.rb +87 -0
- data/lib/cucumber/chef/templates/controller.erb +35 -0
- data/lib/cucumber/chef/templates/env.rb +16 -0
- data/lib/cucumber/chef/templates/example_feature.erb +11 -0
- data/lib/cucumber/chef/templates/example_step.erb +19 -0
- data/lib/cucumber/chef/templates/readme.erb +28 -0
- data/lib/cucumber/chef/templates/ubuntu10.04-gems.erb +43 -0
- data/lib/cucumber/chef/version.rb +5 -0
- data/lib/cucumber/ec2_server_create.rb +99 -0
- data/spec/unit/cucumber_chef_spec.rb +270 -0
- metadata +213 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
module Cucumber
|
2
|
+
module Chef
|
3
|
+
module Handy
|
4
|
+
def create_server(server, ip)
|
5
|
+
create_network_config(server, ip)
|
6
|
+
create_container(server)
|
7
|
+
end
|
8
|
+
|
9
|
+
def create_network_config(name, ip)
|
10
|
+
network_config = File.join("/etc/lxc", name)
|
11
|
+
File.open(network_config, 'w') do |f|
|
12
|
+
f.puts "lxc.network.type = veth"
|
13
|
+
f.puts "lxc.network.flags = up"
|
14
|
+
f.puts "lxc.network.link = br0"
|
15
|
+
f.puts "lxc.network.name = eth0"
|
16
|
+
f.puts "lxc.network.ipv4 = #{ip}/24"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def create_container(name)
|
21
|
+
unless File.exists?("/var/lib/lxc/#{name}")
|
22
|
+
%x[lxc-create -n #{name} -f /etc/lxc/#{name} -t lucid-chef > /dev/null 2>&1 ]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def set_run_list(name, run_list)
|
27
|
+
rl = Hash.new
|
28
|
+
a = Array.new
|
29
|
+
a << run_list
|
30
|
+
rl['run_list'] = a
|
31
|
+
first_boot = File.join('/var/lib/lxc', name, 'rootfs/etc/chef/first-boot.json')
|
32
|
+
File.open(first_boot, 'w') do |f|
|
33
|
+
f.puts rl.to_json
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def run_chef_first_time(name)
|
38
|
+
%x[chroot /var/lib/lxc/#{name}/rootfs /bin/bash -c 'chef-client -j /etc/chef/first-boot.json > /dev/null 2>&1']
|
39
|
+
end
|
40
|
+
|
41
|
+
def run_chef(name)
|
42
|
+
container_path = "/var/lib/lxc/#{name}/rootfs"
|
43
|
+
%x[chroot #{container_path} /bin/bash -c 'chef-client > /dev/null 2>&1']
|
44
|
+
end
|
45
|
+
|
46
|
+
def upload_databag_item(databag, item)
|
47
|
+
databag_item = ::Chef::DataBagItem.new
|
48
|
+
databag_item.data_bag(databag)
|
49
|
+
databag_item.raw_data = item
|
50
|
+
databag_item.save
|
51
|
+
end
|
52
|
+
|
53
|
+
def create_client_rb(orgname)
|
54
|
+
client_rb = File.join('/var/lib/lxc', name, 'rootfs/etc/chef/client.rb')
|
55
|
+
File.open(client_rb, 'w') do |f|
|
56
|
+
f.puts "log_level :info"
|
57
|
+
f.puts "log_location STDOUT"
|
58
|
+
f.puts "chef_server_url 'https://api.opscode.com/organizations/#{orgname}'"
|
59
|
+
f.puts "validation_client_name '#{orgname}-validator'"
|
60
|
+
f.puts "node_name 'cucumber-chef-#{name}'"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def start_container(name)
|
65
|
+
status = %x[lxc-info -n #{name} 2>&1]
|
66
|
+
if status.include?("STOPPED")
|
67
|
+
%x[lxc-start -d -n #{name}]
|
68
|
+
sleep 5
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def stop_container(name)
|
73
|
+
status = %x[lxc-info -n #{name} 2>&1]
|
74
|
+
if status.include?("RUNNING")
|
75
|
+
%x[lxc-destroy -d -n #{name}]
|
76
|
+
sleep 5
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def run_remote_command(remote_server, command)
|
81
|
+
%x[ssh workstation.testlab 'ssh #{remote_server} #{command}']
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
bash -c '
|
2
|
+
(
|
3
|
+
cat <<EOP
|
4
|
+
lxc.network.type = veth
|
5
|
+
lxc.network.flags = up
|
6
|
+
lxc.network.link = br0
|
7
|
+
lxc.network.name = eth0
|
8
|
+
lxc.network.ipv4 = 192.168.10.10/24
|
9
|
+
EOP
|
10
|
+
) > /etc/lxc/controller
|
11
|
+
|
12
|
+
lxc-create -n controller -f /etc/lxc/controller -t lucid-chef
|
13
|
+
|
14
|
+
(
|
15
|
+
cat <<EOP
|
16
|
+
|
17
|
+
log_level :info
|
18
|
+
log_location STDOUT
|
19
|
+
chef_server_url "<%= @config[:chef_server_url] %>"
|
20
|
+
validation_client_name "<%= @config[:validation_client_name] %>"
|
21
|
+
<% if @config[:chef_node_name] == nil %>
|
22
|
+
# Using default node name"
|
23
|
+
<% else %>
|
24
|
+
node_name "<%= @config[:chef_node_name] %>"
|
25
|
+
<% end %>
|
26
|
+
EOP
|
27
|
+
) > /var/lib/lxc/controller/rootfs/etc/chef/client.rb
|
28
|
+
|
29
|
+
cat <<EOP
|
30
|
+
{ "run_list": [ "recipe[cucumber-chef::controller]" ] }
|
31
|
+
EOP
|
32
|
+
) > /var/lib/lxc/controller/rootfs/etc/chef/first-boot.json
|
33
|
+
|
34
|
+
chroot /var/lib/lxc/controller/rootfs /bin/bash -c "chef-client -j /etc/chef/first-boot.json > /dev/null 2>&1"
|
35
|
+
lxc-start -d -n controller && sleep 5 && lxc-start -d -n controller'
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rspec/expectations'
|
4
|
+
require 'chef'
|
5
|
+
require 'cucumber/chef'
|
6
|
+
require 'cucumber/nagios/steps'
|
7
|
+
require 'cucumber/chef/handy'
|
8
|
+
|
9
|
+
class CustomWorld
|
10
|
+
include Cucumber::Chef
|
11
|
+
include Cucumber::Chef::Handy
|
12
|
+
end
|
13
|
+
|
14
|
+
World do
|
15
|
+
CustomWorld.new
|
16
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
Feature: Example feature for <%= @project %>
|
2
|
+
So that I can be learn how to use cucumber-chef
|
3
|
+
As an infrastructure developer
|
4
|
+
I can run an example feature that doesn't do much
|
5
|
+
|
6
|
+
Scenario: Example scenario for <%= @project %>
|
7
|
+
Given I have a remote server
|
8
|
+
And I apply the <%= @project %> role/recipe
|
9
|
+
And run Chef
|
10
|
+
When I connect to the remote server from the test server
|
11
|
+
Then the <% @project %> server behaves as it should
|
@@ -0,0 +1,19 @@
|
|
1
|
+
Given /^I have a remote server$/ do
|
2
|
+
pending # express the regexp above with the code you wish you had
|
3
|
+
end
|
4
|
+
|
5
|
+
Given /^I apply the <%= @project %> role\/recipe$/ do
|
6
|
+
pending # express the regexp above with the code you wish you had
|
7
|
+
end
|
8
|
+
|
9
|
+
Given /^run Chef$/ do
|
10
|
+
pending # express the regexp above with the code you wish you had
|
11
|
+
end
|
12
|
+
|
13
|
+
When /^I connect to the remote server from the test server$/ do
|
14
|
+
pending # express the regexp above with the code you wish you had
|
15
|
+
end
|
16
|
+
|
17
|
+
Then /^the <%= @project %> server behaves as it should$/ do
|
18
|
+
pending # express the regexp above with the code you wish you had
|
19
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
Welcome to the <%= @project %> suite of cucumber-chef tests
|
2
|
+
|
3
|
+
Your general workflow will be to write cucumber features that describe the intended behaviour of '<%= @project %>'. You will then write failing tests by writing steps to test the b$
|
4
|
+
|
5
|
+
You will then want to create a '<%= @project %>' cookbook, and write recipes that make your tests pass. Upload your cookbook to the Opscode Platform, and then push your cucumber-ch$
|
6
|
+
|
7
|
+
cucumber-chef upload <%= @project %>
|
8
|
+
|
9
|
+
Then run your tests with:
|
10
|
+
|
11
|
+
cucumber-chef test <%= @project %>
|
12
|
+
|
13
|
+
For an example feature, take a look at ./<%= @project %>/features/example.feature
|
14
|
+
|
15
|
+
For an example step definition, look at ./<%= @project %>/features/example.feature
|
16
|
+
|
17
|
+
To get started, you'll need to configure cucumber-chef to use your own Opscode Chef platform credentials, and AWS EC2 keys. You can generate a sample config with:
|
18
|
+
|
19
|
+
cucumber-chef genconfig
|
20
|
+
|
21
|
+
This will drop a .cucumber-chef config file in the home directory of the user with which you ran the cucumber-chef command. You'll need to edit the file in order to carry out setup, upload or test functionality.
|
22
|
+
|
23
|
+
One you've got a configuration in place, run:
|
24
|
+
|
25
|
+
cucumber-chef setup
|
26
|
+
|
27
|
+
This will create what we call a 'test lab' in EC2 in which tests will be run.
|
28
|
+
|
@@ -0,0 +1,43 @@
|
|
1
|
+
bash -c '
|
2
|
+
if [ ! -f /usr/bin/chef-client ]; then
|
3
|
+
apt-get update
|
4
|
+
apt-get install -y ruby ruby1.8-dev build-essential wget libruby-extras libruby1.8-extras
|
5
|
+
cd /tmp
|
6
|
+
wget http://production.cf.rubygems.org/rubygems/rubygems-1.3.7.tgz
|
7
|
+
tar zxf rubygems-1.3.7.tgz
|
8
|
+
cd rubygems-1.3.7
|
9
|
+
ruby setup.rb --no-format-executable
|
10
|
+
fi
|
11
|
+
gem install ohai chef --no-rdoc --no-ri --verbose <%= '--prerelease' if @config[:prerelease] %>
|
12
|
+
|
13
|
+
mkdir -p /etc/chef
|
14
|
+
|
15
|
+
(
|
16
|
+
cat <<'EOP'
|
17
|
+
<%= IO.read(@config[:validation_key]) %>
|
18
|
+
EOP
|
19
|
+
) > /tmp/validation.pem
|
20
|
+
awk NF /tmp/validation.pem > /etc/chef/validation.pem
|
21
|
+
rm /tmp/validation.pem
|
22
|
+
|
23
|
+
(
|
24
|
+
cat <<'EOP'
|
25
|
+
log_level :info
|
26
|
+
log_location STDOUT
|
27
|
+
chef_server_url "<%= @config[:chef_server_url] %>"
|
28
|
+
validation_client_name "<%= @config[:validation_client_name] %>"
|
29
|
+
<% if @config[:chef_node_name] == nil %>
|
30
|
+
# Using default node name"
|
31
|
+
<% else %>
|
32
|
+
node_name "<%= @config[:chef_node_name] %>"
|
33
|
+
<% end %>
|
34
|
+
EOP
|
35
|
+
) > /etc/chef/client.rb
|
36
|
+
|
37
|
+
(
|
38
|
+
cat <<'EOP'
|
39
|
+
<%= { "run_list" => @run_list }.to_json %>
|
40
|
+
EOP
|
41
|
+
) > /etc/chef/first-boot.json
|
42
|
+
|
43
|
+
/usr/bin/chef-client -j /etc/chef/first-boot.json'
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'fog'
|
2
|
+
require 'socket'
|
3
|
+
require 'chef/knife'
|
4
|
+
require 'chef/knife/bootstrap'
|
5
|
+
require 'chef/json_compat'
|
6
|
+
|
7
|
+
class Chef
|
8
|
+
class Knife
|
9
|
+
class Ec2ServerCreate < Knife
|
10
|
+
|
11
|
+
attr_accessor :initial_sleep_delay
|
12
|
+
|
13
|
+
def tcp_test_ssh(hostname)
|
14
|
+
tcp_socket = TCPSocket.new(hostname, 22)
|
15
|
+
readable = IO.select([tcp_socket], nil, nil, 5)
|
16
|
+
if readable
|
17
|
+
Chef::Log.debug("sshd accepting connections on #{hostname}, banner is #{tcp_socket.gets}")
|
18
|
+
yield
|
19
|
+
true
|
20
|
+
else
|
21
|
+
false
|
22
|
+
end
|
23
|
+
rescue Errno::ETIMEDOUT
|
24
|
+
false
|
25
|
+
rescue Errno::ECONNREFUSED
|
26
|
+
sleep 2
|
27
|
+
false
|
28
|
+
ensure
|
29
|
+
tcp_socket && tcp_socket.close
|
30
|
+
end
|
31
|
+
|
32
|
+
def run
|
33
|
+
require 'fog'
|
34
|
+
require 'highline'
|
35
|
+
require 'net/ssh/multi'
|
36
|
+
require 'readline'
|
37
|
+
|
38
|
+
$stdout.sync = true
|
39
|
+
|
40
|
+
connection = Fog::Compute.new(
|
41
|
+
:provider => 'AWS',
|
42
|
+
:aws_access_key_id => Chef::Config[:knife][:aws_access_key_id],
|
43
|
+
:aws_secret_access_key => Chef::Config[:knife][:aws_secret_access_key],
|
44
|
+
:region => #REGION
|
45
|
+
)
|
46
|
+
|
47
|
+
# WHAT IS THIS FOR?
|
48
|
+
ami = connection.images.get(locate_config_value(:image))
|
49
|
+
|
50
|
+
server_def = {
|
51
|
+
:image_id => locate_config_value(:image),
|
52
|
+
:groups => config[:security_groups],
|
53
|
+
:flavor_id => locate_config_value(:flavor),
|
54
|
+
:key_name => Chef::Config[:knife][:aws_ssh_key_id],
|
55
|
+
:availability_zone => Chef::Config[:knife][:availability_zone]
|
56
|
+
}
|
57
|
+
|
58
|
+
server = connection.servers.create(server_def)
|
59
|
+
|
60
|
+
puts "Instance ID: #{server.id}"
|
61
|
+
print "\n#{h.color("Waiting for server", :magenta)}"
|
62
|
+
|
63
|
+
# wait for it to be ready to do stuff
|
64
|
+
server.wait_for { print "."; ready? }
|
65
|
+
|
66
|
+
puts("\n")
|
67
|
+
|
68
|
+
puts "Public IP Address #{server.public_ip_address}"
|
69
|
+
|
70
|
+
print "\n#{h.color("Waiting for sshd", :magenta)}"
|
71
|
+
|
72
|
+
print(".") until tcp_test_ssh(server.dns_name) { sleep @initial_sleep_delay ||= 10; puts("done") }
|
73
|
+
|
74
|
+
bootstrap_for_node(server).run
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
def bootstrap_for_node(server)
|
79
|
+
bootstrap = Chef::Knife::Bootstrap.new
|
80
|
+
bootstrap.name_args = [server.dns_name]
|
81
|
+
bootstrap.config[:run_list] = config[:run_list]
|
82
|
+
bootstrap.config[:ssh_user] = config[:ssh_user]
|
83
|
+
bootstrap.config[:identity_file] = config[:identity_file]
|
84
|
+
bootstrap.config[:chef_node_name] = config[:chef_node_name] || server.id
|
85
|
+
bootstrap.config[:prerelease] = config[:prerelease]
|
86
|
+
bootstrap.config[:distro] = locate_config_value(:distro)
|
87
|
+
bootstrap.config[:use_sudo] = true
|
88
|
+
bootstrap.config[:template_file] = locate_config_value(:template_file)
|
89
|
+
bootstrap.config[:environment] = config[:environment]
|
90
|
+
bootstrap
|
91
|
+
end
|
92
|
+
|
93
|
+
def locate_config_value(key)
|
94
|
+
key = key.to_sym
|
95
|
+
Chef::Config[:knife][key] || config[key]
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,270 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "bundler/setup"
|
3
|
+
require File.join(File.dirname(__FILE__), "../../lib/cucumber-chef")
|
4
|
+
|
5
|
+
def tcp_test_ssh(hostname)
|
6
|
+
tcp_socket = TCPSocket.new(hostname, 22)
|
7
|
+
IO.select([tcp_socket], nil, nil, 5)
|
8
|
+
rescue Errno::ETIMEDOUT
|
9
|
+
false
|
10
|
+
rescue Errno::EPERM
|
11
|
+
false
|
12
|
+
rescue Errno::ECONNREFUSED
|
13
|
+
sleep 2
|
14
|
+
false
|
15
|
+
# This happens on EC2 quite often
|
16
|
+
rescue Errno::EHOSTUNREACH
|
17
|
+
sleep 2
|
18
|
+
false
|
19
|
+
ensure
|
20
|
+
tcp_socket && tcp_socket.close
|
21
|
+
end
|
22
|
+
|
23
|
+
describe Cucumber::Chef::Config do
|
24
|
+
describe "when configuration is missing" do
|
25
|
+
it "should raise if it cannot find a configuration" do
|
26
|
+
begin
|
27
|
+
chef_dir = File.expand_path("~/.chef")
|
28
|
+
config_file = File.join(chef_dir, "knife.rb")
|
29
|
+
FileUtils.mv(config_file, File.join(chef_dir, "knife.rb.bak"))
|
30
|
+
expect { subject.config }.to raise_error(Cucumber::Chef::ConfigError)
|
31
|
+
ensure
|
32
|
+
FileUtils.mv(File.join(chef_dir, "knife.rb.bak"), config_file)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "when configuration is invalid" do
|
38
|
+
config_dir = File.join(File.dirname(__FILE__), "../../.chef")
|
39
|
+
|
40
|
+
before(:all) { FileUtils.mkdir_p(config_dir) }
|
41
|
+
after(:all) { FileUtils.rm_rf(config_dir) }
|
42
|
+
|
43
|
+
it "should complain about missing keys" do
|
44
|
+
config = "node_name ''"
|
45
|
+
File.open(Pathname(config_dir) + "knife.rb", 'w') { |f| f.puts config }
|
46
|
+
values, missing_keys = subject.display
|
47
|
+
missing_keys.should include("node_name")
|
48
|
+
missing_keys.should include("knife[:aws_access_key_id]")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "when configuration is valid" do
|
53
|
+
it "should find the configuration" do
|
54
|
+
values, missing_keys = subject.display
|
55
|
+
missing_keys.should be_empty
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should display the configuration values" do
|
59
|
+
values, missing_keys = subject.display
|
60
|
+
output = values.join("\n")
|
61
|
+
output.should match(/node_name:/)
|
62
|
+
output.should match(/knife\[:aws_secret_access_key\]:/)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe Cucumber::Chef::Provisioner do
|
68
|
+
before(:all) do
|
69
|
+
@config = subject.config
|
70
|
+
@config[:mode] = "test"
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "verify_opscode_platform_credentials" do
|
74
|
+
describe "when configuration is invalid" do
|
75
|
+
config_dir = File.join(File.dirname(__FILE__), "../../.chef")
|
76
|
+
knife_file = File.join(config_dir, "knife.rb")
|
77
|
+
|
78
|
+
before(:all) do
|
79
|
+
FileUtils.mkdir_p(config_dir)
|
80
|
+
end
|
81
|
+
|
82
|
+
after(:all) do
|
83
|
+
FileUtils.rm_rf(config_dir)
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "when node name is missing" do
|
87
|
+
it "should raise" do
|
88
|
+
config = "node_name ''"
|
89
|
+
File.open(knife_file, 'w') { |f| f.puts config }
|
90
|
+
expect {
|
91
|
+
subject.verify_opscode_platform_credentials(subject.config)
|
92
|
+
}.to raise_error(Cucumber::Chef::ProvisionerError)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "when node name is invalid" do
|
97
|
+
it "should raise" do
|
98
|
+
config = "node_name 'REALLYBOGUSORGNAME'"
|
99
|
+
File.open(knife_file, 'w') { |f| f.puts config }
|
100
|
+
expect {
|
101
|
+
subject.verify_opscode_platform_credentials(subject.config)
|
102
|
+
}.to raise_error(Cucumber::Chef::ProvisionerError)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "when configuration is valid" do
|
108
|
+
it "should not raise" do
|
109
|
+
subject.verify_opscode_platform_credentials(subject.config)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "verify_aws_credentials" do
|
115
|
+
describe "when configuration is invalid" do
|
116
|
+
config_dir = File.join(File.dirname(__FILE__), "../../.chef")
|
117
|
+
knife_file = File.join(config_dir, "knife.rb")
|
118
|
+
|
119
|
+
before(:all) do
|
120
|
+
FileUtils.mkdir_p(config_dir)
|
121
|
+
end
|
122
|
+
|
123
|
+
after(:all) do
|
124
|
+
FileUtils.rm_rf(config_dir)
|
125
|
+
end
|
126
|
+
|
127
|
+
describe "when configuration is invalid" do
|
128
|
+
it "should raise" do
|
129
|
+
config = "knife[:aws_access_key_id] = ''"
|
130
|
+
File.open(knife_file, 'w') { |f| f.puts config }
|
131
|
+
expect {
|
132
|
+
subject.verify_aws_credentials(subject.config)
|
133
|
+
}.to raise_error(Cucumber::Chef::ProvisionerError)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
describe "when configuration is valid" do
|
139
|
+
it "should not raise" do
|
140
|
+
subject.verify_aws_credentials(subject.config)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
describe "build_test_lab" do
|
146
|
+
after(:each) do
|
147
|
+
config = @config[:knife]
|
148
|
+
connection = Fog::Compute.new(:provider => 'AWS',
|
149
|
+
:aws_access_key_id => config[:aws_access_key_id],
|
150
|
+
:aws_secret_access_key => config[:aws_secret_access_key],
|
151
|
+
:region => config[:region])
|
152
|
+
connection.servers.each do |s|
|
153
|
+
s.destroy if s.tags['cucumber-chef'] == 'test' && s.state == 'running'
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should spin up a ec2 instance", :slow => true do
|
158
|
+
output = StringIO.new
|
159
|
+
subject.build_test_lab(@config, output)
|
160
|
+
output.rewind
|
161
|
+
output.read.should match(/Platform provisioned/)
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should only spin up one ec2 instance", :slow => true do
|
165
|
+
subject.build_test_lab(@config, StringIO.new)
|
166
|
+
expect {
|
167
|
+
subject.build_test_lab(@config, StringIO.new)
|
168
|
+
}.to raise_error(Cucumber::Chef::ProvisionerError)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
describe "upload_cookbook" do
|
173
|
+
before(:each) do
|
174
|
+
begin
|
175
|
+
cookbook_path = File.expand_path("cookbooks/cucumber-chef")
|
176
|
+
version_loader = ::Chef::Cookbook::CookbookVersionLoader.new(cookbook_path)
|
177
|
+
version_loader.load_cookbooks
|
178
|
+
version = version_loader.cookbook_version
|
179
|
+
version.destroy
|
180
|
+
rescue Net::HTTPServerException => err
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
it "should upload the cucumber-chef cookbook" do
|
185
|
+
subject.upload_cookbook(@config)
|
186
|
+
::Chef::CookbookVersion.list["cucumber-chef"].should be
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
describe "upload_role" do
|
191
|
+
before(:each) do
|
192
|
+
begin
|
193
|
+
role_path = File.expand_path("cookbooks/cucumber-chef/roles")
|
194
|
+
::Chef::Config[:role_path] = role_path
|
195
|
+
role = ::Chef::Role.from_disk("test_lab_test")
|
196
|
+
role.destroy
|
197
|
+
rescue Net::HTTPServerException => err
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
it "should upload the test_lab role" do
|
202
|
+
subject.upload_role(@config)
|
203
|
+
::Chef::Role.list["test_lab_test"].should be
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
describe "bootstrap_node" do
|
208
|
+
before(:each) do
|
209
|
+
server = subject.build_test_lab(@config, StringIO.new)
|
210
|
+
@dns_name = server.dns_name
|
211
|
+
puts "Hanging around..." until tcp_test_ssh(server.public_ip_address)
|
212
|
+
puts "Got ssh..."
|
213
|
+
sleep(10)
|
214
|
+
subject.upload_cookbook(@config)
|
215
|
+
subject.upload_role(@config)
|
216
|
+
end
|
217
|
+
|
218
|
+
after(:each) do
|
219
|
+
config = @config[:knife]
|
220
|
+
connection = Fog::Compute.new(:provider => 'AWS',
|
221
|
+
:aws_access_key_id => config[:aws_access_key_id],
|
222
|
+
:aws_secret_access_key => config[:aws_secret_access_key],
|
223
|
+
:region => config[:region])
|
224
|
+
connection.servers.each do |s|
|
225
|
+
s.destroy if s.tags['cucumber-chef'] == 'test' && s.state == 'running'
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
it "should set up platform as a chef client and apply test-lab role" do
|
230
|
+
bootstrapper = subject.bootstrap_node(@dns_name, @config)
|
231
|
+
bootstrapper.run
|
232
|
+
# DEBUG: puts bootstrapper.ui.stdout.string
|
233
|
+
node = ::Chef::Node.load("cucumber-chef-test-lab")
|
234
|
+
node.run_list.to_s.should match(/role\[test_lab_test\]/)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
describe "build_controller" do
|
239
|
+
|
240
|
+
before(:each) do
|
241
|
+
server = subject.build_test_lab(@config, StringIO.new)
|
242
|
+
@dns_name = server.dns_name
|
243
|
+
puts "Hanging around..." until tcp_test_ssh(server.public_ip_address)
|
244
|
+
puts "Got ssh..."
|
245
|
+
sleep(10)
|
246
|
+
subject.upload_cookbook(@config)
|
247
|
+
subject.upload_role(@config)
|
248
|
+
subject.bootstrap_node(@dns_name, @config).run
|
249
|
+
end
|
250
|
+
|
251
|
+
after(:each) do
|
252
|
+
config = @config[:knife]
|
253
|
+
connection = Fog::Compute.new(:provider => 'AWS',
|
254
|
+
:aws_access_key_id => config[:aws_access_key_id],
|
255
|
+
:aws_secret_access_key => config[:aws_secret_access_key],
|
256
|
+
:region => config[:region])
|
257
|
+
connection.servers.each do |s|
|
258
|
+
s.destroy if s.tags['cucumber-chef'] == 'test' && s.state == 'running'
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
it "should build a cucumber-chef controller" do
|
263
|
+
controller_builder = subject.build_controller(@dns_name, @config)
|
264
|
+
controller_builder.run
|
265
|
+
puts controller_builder.ui.stdout.string
|
266
|
+
end
|
267
|
+
|
268
|
+
end
|
269
|
+
|
270
|
+
end
|