class Cucumber::Chef::Provisioner

Attributes

test_lab[RW]

Public Class Methods

new(test_lab, ui=ZTK::UI.new) click to toggle source
# File lib/cucumber/chef/provisioner.rb, line 32
def initialize(test_lab, ui=ZTK::UI.new)
  test_lab.nil? and raise ProvisionerError, "You must supply a test lab!"

  @test_lab = test_lab
  @ui       = ui

  @cookbooks_path = File.join(Cucumber::Chef.root_dir, "chef_repo", "cookbooks")
  @roles_path = File.join(Cucumber::Chef.root_dir, "chef_repo", "roles")
end

Public Instance Methods

build() click to toggle source
# File lib/cucumber/chef/provisioner.rb, line 44
def build
  upload_chef_repo
  bootstrap
  wait_for_chef_server

  download_chef_credentials
  download_ssh_credentials

  reboot_test_lab
end

Private Instance Methods

bootstrap() click to toggle source
# File lib/cucumber/chef/provisioner.rb, line 86
def bootstrap
  raise ProvisionerError, "You must have the environment variable 'USER' set." if !Cucumber::Chef::Config.user

  ZTK::Benchmark.bench(:message => "Bootstrapping #{Cucumber::Chef::Config.provider.upcase} instance", :mark => "completed in %0.4f seconds.", :ui => @ui) do
    server_name           = @test_lab.ip
    chef_solo_attributes  = build_chef_solo_attributes(server_name)
    context               = build_context(server_name, chef_solo_attributes)

    bootstrap_template = File.join(Cucumber::Chef.root_dir, "lib", "cucumber", "chef", "templates", "bootstrap", "ubuntu-precise-omnibus.erb")

    local_bootstrap_file = Tempfile.new("bootstrap")
    local_bootstrap_filename = local_bootstrap_file.path
    local_bootstrap_file.write(::ZTK::Template.render(bootstrap_template, context))
    local_bootstrap_file.close

    remote_bootstrap_filename = File.join('/tmp', 'cucumber-chef-bootstrap.sh')

    @test_lab.bootstrap_ssh.upload(local_bootstrap_filename, remote_bootstrap_filename)

    local_bootstrap_file.unlink

    command = "sudo /bin/bash #{remote_bootstrap_filename}"
    @test_lab.bootstrap_ssh.exec(command, :silence => true)
  end
end
build_chef_solo_10_attributes(server_name) click to toggle source
# File lib/cucumber/chef/provisioner.rb, line 112
def build_chef_solo_10_attributes(server_name)
  {
    "chef-server" => {
      "webui_enabled" => true
    },
    "run_list" => %w(recipe[chef-server::rubygems-install] recipe[chef-server::apache-proxy] role[test_lab])
  }
end
build_chef_solo_11_attributes(server_name) click to toggle source
# File lib/cucumber/chef/provisioner.rb, line 121
def build_chef_solo_11_attributes(server_name)
  {
    "chef-server" => {
      "api_fqdn" => server_name,
      "nginx" => {
        "enable_non_ssl" => true,
        "server_name" => server_name,
        "url" => "https://#{server_name}"
      },
      "lb" => {
        "fqdn" => server_name
      },
      "bookshelf" => {
        "vip" => server_name
      },
      "chef_server_webui" => {
        "enable" => true
      },
      "version" => Cucumber::Chef::Config.chef[:version],
      "prereleases" => Cucumber::Chef::Config.chef[:prereleases],
      "nightlies" => Cucumber::Chef::Config.chef[:nightlies]
    },
    "run_list" => %w(recipe[chef-server::default] role[test_lab])
  }
end
build_chef_solo_attributes(server_name) click to toggle source
# File lib/cucumber/chef/provisioner.rb, line 158
def build_chef_solo_attributes(server_name)
  # TODO: This really should switch on the version number.
  chef_solo_attributes = case Cucumber::Chef.chef_pre_11
  when true then
    build_chef_solo_10_attributes(server_name)
  when false then
    build_chef_solo_11_attributes(server_name)
  end

  chef_solo_attributes.merge!(build_cucumber_chef_attributes(server_name))

  chef_solo_attributes
end
build_context(server_name, chef_solo_attributes) click to toggle source
# File lib/cucumber/chef/provisioner.rb, line 172
def build_context(server_name, chef_solo_attributes)
  {
    :server_name => server_name,
    :lab_user => Cucumber::Chef.lab_user,
    :chef_pre_11 => Cucumber::Chef.chef_pre_11,
    :chef_solo_attributes => chef_solo_attributes,
    :chef_version => Cucumber::Chef::Config.chef[:version],
    :chef_validator => (Cucumber::Chef.chef_pre_11 ? '/etc/chef/validation.pem' : '/etc/chef-server/chef-validator.pem'),
    :chef_webui => (Cucumber::Chef.chef_pre_11 ? '/etc/chef/webui.pem' : '/etc/chef-server/chef-webui.pem'),
    :chef_admin => (Cucumber::Chef.chef_pre_11 ? '/etc/chef/admin.pem' : '/etc/chef-server/admin.pem'),
    :default_password => Cucumber::Chef::Config.chef[:default_password],
    :user => Cucumber::Chef::Config.user,
    :hostname_short => Cucumber::Chef.lab_hostname_short,
    :hostname_full => Cucumber::Chef.lab_hostname_full
  }
end
build_cucumber_chef_attributes(server_name) click to toggle source
# File lib/cucumber/chef/provisioner.rb, line 147
def build_cucumber_chef_attributes(server_name)
  {
    "cucumber_chef" => {
      "version" => Cucumber::Chef::VERSION,
      "prerelease" => Cucumber::Chef::Config.prerelease,
      "lab_user" => Cucumber::Chef.lab_user,
      "lxc_user" => Cucumber::Chef.lxc_user
    }
  }
end
download_chef_credentials() click to toggle source
# File lib/cucumber/chef/provisioner.rb, line 191
def download_chef_credentials
  ZTK::Benchmark.bench(:message => "Downloading chef credentials", :mark => "completed in %0.4f seconds.", :ui => @ui) do
    local_path = File.dirname(Cucumber::Chef.chef_identity)
    @ui.logger.debug { "local_path == #{local_path.inspect}" }

    remote_path = File.join(Cucumber::Chef.bootstrap_user_home_dir, ".chef")
    @ui.logger.debug { "remote_path == #{remote_path.inspect}" }

    files = [ File.basename(Cucumber::Chef.chef_identity) ]
    if (Cucumber::Chef.chef_pre_11 == true)
      files << "validation.pem"
    else
      files << "chef-validator.pem"
    end
    files.each do |file|
      @ui.logger.debug { "file == #{file.inspect}" }

      @test_lab.bootstrap_ssh.download(File.join(remote_path, file), File.join(local_path, file))
    end
  end
end
download_ssh_credentials() click to toggle source
# File lib/cucumber/chef/provisioner.rb, line 215
def download_ssh_credentials
  ZTK::Benchmark.bench(:message => "Downloading SSH credentials", :mark => "completed in %0.4f seconds.", :ui => @ui) do
    local_path = File.join(Cucumber::Chef.home_dir, Cucumber::Chef::Config.provider.to_s)

    users = {
      Cucumber::Chef.lab_user => Cucumber::Chef.lab_user_home_dir,
      Cucumber::Chef.lxc_user => Cucumber::Chef.lxc_user_home_dir
    }

    users.each do |username, home_dir|
      identity_file = File.join(home_dir, ".ssh", "id_rsa")
      temp_file = File.join("/tmp", "id_rsa-#{username}")
      local_file = File.join(local_path, "id_rsa-#{username}")

      @test_lab.bootstrap_ssh.exec(%(sudo cp -v #{identity_file} #{temp_file}), :silence => true)
      @test_lab.bootstrap_ssh.exec(%(sudo chown -v #{Cucumber::Chef.bootstrap_user}:#{Cucumber::Chef.bootstrap_user} #{temp_file}), :silence => true)

      File.exists?(local_file) and File.delete(local_file)
      @test_lab.bootstrap_ssh.download(temp_file, local_file)
      File.chmod(0600, local_file)
    end
  end
end
reboot_test_lab() click to toggle source
# File lib/cucumber/chef/provisioner.rb, line 249
def reboot_test_lab
  ZTK::Benchmark.bench(:message => "Rebooting the test lab", :mark => "completed in %0.4f seconds.", :ui => @ui) do
    command = "sudo reboot"
    @test_lab.bootstrap_ssh.exec(command, :silence => true)
    sleep(10)
    ZTK::TCPSocketCheck.new(:host => @test_lab.ip, :port => @test_lab.port, :wait => 120).wait
  end

  wait_for_chef_server
end
upload_chef_repo() click to toggle source
# File lib/cucumber/chef/provisioner.rb, line 60
def upload_chef_repo
  ZTK::Benchmark.bench(:message => "Uploading embedded chef-repo", :mark => "completed in %0.4f seconds.", :ui => @ui) do
    local_path = File.join(Cucumber::Chef.root_dir, "chef_repo")
    @ui.logger.debug { "local_path == #{local_path.inspect}" }

    remote_path = File.join("/tmp", "chef-solo")
    @ui.logger.debug { "remote_path == #{remote_path.inspect}" }

    # FIXME!
    # there seems to be a major difference between net-sftp v2.0.5 and
    # v2.1.1; under v2.0.5 the remote_path is expected to exist already so
    # if it is not in place mkdir fails with Net::SFTP::StatusException on
    # the Net::SFTP mkdir internal call triggered by a Net::SFTP upload
    # call
    @test_lab.bootstrap_ssh.exec(%(sudo rm -vrf #{remote_path}), :silence => true)
    begin
      @test_lab.bootstrap_ssh.upload(local_path, remote_path)
    rescue Net::SFTP::StatusException => e
      @test_lab.bootstrap_ssh.exec(%(mkdir -vp #{remote_path}), :silence => true)
      retry
    end
  end
end
wait_for_chef_server() click to toggle source
# File lib/cucumber/chef/provisioner.rb, line 241
def wait_for_chef_server
  ZTK::Benchmark.bench(:message => "Waiting for the chef-server-api HTTPS", :mark => "responded after %0.4f seconds.", :ui => @ui) do
    ZTK::TCPSocketCheck.new(:host => @test_lab.ip, :port => 443, :data => "GET", :wait => 120).wait
  end
end