Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for WinRM Transport and Windows-based instances #154

Merged
merged 4 commits into from
Mar 24, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -396,9 +396,10 @@ section of the Vagrant documentation.
To prevent this value from being rendered in the default Vagrantfile, you can
set this value to `false`.

The default will be computed from the name of the instance. For
example, the instance was called "default-fuzz-9" will produce a default
`vm_hostname` value of `"default-fuzz-9.vagrantup.com"`.
The default will be computed from the name of the instance. For example, the
instance was called "default-fuzz-9" will produce a default `vm_hostname` value
of `"default-fuzz-9"`. For Windows-based platforms, a default of `nil` is used
to save on boot time and potential rebooting.

## <a name="development"></a> Development

Expand Down
2 changes: 1 addition & 1 deletion kitchen-vagrant.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Gem::Specification.new do |gem|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
gem.require_paths = ["lib"]

gem.add_dependency "test-kitchen", "~> 1.0"
gem.add_dependency "test-kitchen", "= 1.4.0.beta.1"

gem.add_development_dependency "countloc", "~> 0.4"
gem.add_development_dependency "rake"
Expand Down
71 changes: 62 additions & 9 deletions lib/kitchen/driver/vagrant.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ module Driver
# Vagrant driver for Kitchen. It communicates to Vagrant via the CLI.
#
# @author Fletcher Nichol <[email protected]>
class Vagrant < Kitchen::Driver::SSHBase
class Vagrant < Kitchen::Driver::Base

include ShellOut

default_config(:box) { |driver| driver.default_box }
required_config :box
Expand All @@ -46,6 +48,10 @@ class Vagrant < Kitchen::Driver::SSHBase

default_config :network, []

default_config :password do |driver|
"vagrant" if driver.winrm_transport?
end

default_config :pre_create_command, nil

default_config :provision, false
Expand All @@ -58,13 +64,20 @@ class Vagrant < Kitchen::Driver::SSHBase

default_config :synced_folders, []

default_config :username do |driver|
"vagrant" if driver.winrm_transport?
end

default_config :vagrantfile_erb,
File.join(File.dirname(__FILE__), "../../../templates/Vagrantfile.erb")
expand_path_for :vagrantfile_erb

default_config :vagrantfiles, []
expand_path_for :vagrantfiles

default_config(:vm_hostname) { |driver| driver.instance.name }
default_config(:vm_hostname) do |driver|
driver.windows_os? ? nil : driver.instance.name
end

no_parallel_for :create, :destroy

Expand All @@ -77,6 +90,7 @@ def create(state)
run_pre_create_command
run_vagrant_up
update_state(state)
instance.transport.connection(state).wait_until_ready
info("Vagrant instance #{instance.to_str} created.")
end

Expand Down Expand Up @@ -128,9 +142,7 @@ def destroy(state)
# @raise [ClientError] if instance parameter is nil
def finalize_config!(instance)
super
config[:vagrantfiles] = config[:vagrantfiles].map do |path|
File.expand_path(path, config[:kitchen_root])
end
finalize_vm_hostname!
finalize_pre_create_command!
finalize_synced_folders!
self
Expand All @@ -152,6 +164,13 @@ def verify_dependencies
end
end

# @return [TrueClass,FalseClass] whether or not the transport's name
# implies a WinRM-based transport
# @api private
def winrm_transport?
instance.transport.name.downcase =~ /win_?rm/
end

protected

WEBSITE = "http://www.vagrantup.com/downloads.html".freeze
Expand Down Expand Up @@ -223,6 +242,18 @@ def finalize_synced_folders!
end
end

# Truncates the length of `:vm_hostname` to 12 characters for
# Windows-based operating systems.
#
# @api private
def finalize_vm_hostname!
string = config[:vm_hostname]

if windows_os? && string.is_a?(String) && string.size >= 12
config[:vm_hostname] = "#{string[0...10]}-#{string[-1]}"
end
end

# Renders the Vagrantfile ERb template.
#
# @return [String] the contents for a Vagrantfile
Expand Down Expand Up @@ -250,6 +281,22 @@ def run(cmd, options = {})
run_command(cmd, { :cwd => vagrant_root }.merge(options))
end

# Delegates to Kitchen::ShellOut.run_command, overriding some default
# options:
#
# * `:use_sudo` defaults to the value of `config[:use_sudo]` in the
# Driver object
# * `:log_subject` defaults to a String representation of the Driver's
# class name
#
# @see Kitchen::ShellOut#run_command
def run_command(cmd, options = {})
merged = {
:use_sudo => config[:use_sudo], :log_subject => name
}.merge(options)
super(cmd, merged)
end

# Runs a local command before `vagrant up` has been called.
#
# @api private
Expand Down Expand Up @@ -288,10 +335,16 @@ def update_state(state)
hash = vagrant_ssh_config

state[:hostname] = hash["HostName"]
state[:username] = hash["User"]
state[:ssh_key] = hash["IdentityFile"]
state[:port] = hash["Port"]
state[:proxy_command] = hash["ProxyCommand"] if hash["ProxyCommand"]

if winrm_transport?
state[:username] = config[:username]
state[:password] = config[:password]
else
state[:username] = hash["User"]
state[:ssh_key] = hash["IdentityFile"]
state[:port] = hash["Port"]
state[:proxy_command] = hash["ProxyCommand"] if hash["ProxyCommand"]
end
end

# @return [String] full local path to the directory containing the
Expand Down
134 changes: 108 additions & 26 deletions spec/kitchen/driver/vagrant_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@

require "kitchen/driver/vagrant"
require "kitchen/provisioner/dummy"
require "kitchen/transport/dummy"
require "kitchen/verifier/dummy"

describe Kitchen::Driver::Vagrant do

Expand All @@ -31,8 +33,9 @@
let(:config) { { :kitchen_root => "/kroot" } }
let(:platform) { Kitchen::Platform.new(:name => "fooos-99") }
let(:suite) { Kitchen::Suite.new(:name => "suitey") }
let(:busser) { double("busser") }
let(:verifier) { Kitchen::Verifier::Dummy.new }
let(:provisioner) { Kitchen::Provisioner::Dummy.new }
let(:transport) { Kitchen::Transport::Dummy.new }
let(:state_file) { double("state_file") }
let(:state) { Hash.new }
let(:env) { Hash.new }
Expand All @@ -47,12 +50,13 @@

let(:instance) do
Kitchen::Instance.new(
:busser => busser,
:verifier => verifier,
:driver => driver_object,
:logger => logger,
:suite => suite,
:platform => platform,
:provisioner => provisioner,
:transport => transport,
:state_file => state_file
)
end
Expand Down Expand Up @@ -295,14 +299,60 @@
)
end

it "sets :vm_hostname to the instance name by default" do
expect(driver[:vm_hostname]).to eq("suitey-fooos-99")
context "for unix os_types" do

before { allow(platform).to receive(:os_type).and_return("unix") }

it "sets :vm_hostname to the instance name by default" do
expect(driver[:vm_hostname]).to eq("suitey-fooos-99")
end

it "sets :vm_hostname to a custom value" do
config[:vm_hostname] = "okay"

expect(driver[:vm_hostname]).to eq("okay")
end
end

context "for windows os_types" do

before { allow(platform).to receive(:os_type).and_return("windows") }

it "sets :vm_hostname to nil by default" do
expect(driver[:vm_hostname]).to eq(nil)
end

it "sets :vm_hostname to a custom value, truncated to 12 chars" do
config[:vm_hostname] = "this-is-a-pretty-long-name-ya-think"

expect(driver[:vm_hostname]).to eq("this-is-a--k")
end
end

it "sets :vm_hostname to a custom value" do
config[:vm_hostname] = "okay"
context "for non-WinRM-based transports" do

before { allow(transport).to receive(:name).and_return("Coolness") }

it "sets :username to nil by default" do
expect(driver[:username]).to eq(nil)
end

expect(driver[:vm_hostname]).to eq("okay")
it "sets :password to nil by default" do
expect(driver[:password]).to eq(nil)
end
end

context "for WinRM-based transports" do

before { allow(transport).to receive(:name).and_return("WinRM") }

it "sets :username to vagrant by default" do
expect(driver[:username]).to eq("vagrant")
end

it "sets :password to vagrant by default" do
expect(driver[:password]).to eq("vagrant")
end
end
end

Expand Down Expand Up @@ -369,6 +419,14 @@
expect(File.exist?(File.join(vagrant_root, "Vagrantfile"))).to eq(true)
end

it "calls Transport's #wait_until_ready" do
conn = double("connection")
allow(transport).to receive(:connection).with(state).and_return(conn)
expect(conn).to receive(:wait_until_ready)

cmd
end

it "logs the Vagrantfile contents on debug level" do
cmd

Expand Down Expand Up @@ -448,35 +506,59 @@
expect(state).to include(:hostname => "192.168.32.64")
end

it "sets :username from ssh-config" do
cmd
context "for non-WinRM-based transports" do

expect(state).to include(:username => "vagrant")
end
before { allow(transport).to receive(:name).and_return("Coolness") }

it "sets :ssh_key from ssh-config" do
cmd
it "sets :username from ssh-config" do
cmd

expect(state).to include(:ssh_key => "/path/to/private_key")
end
expect(state).to include(:username => "vagrant")
end

it "sets :port from ssh-config" do
cmd
it "sets :ssh_key from ssh-config" do
cmd

expect(state).to include(:port => "2022")
end
expect(state).to include(:ssh_key => "/path/to/private_key")
end

it "does not set :proxy_command by default" do
cmd
it "sets :port from ssh-config" do
cmd

expect(state).to include(:port => "2022")
end

it "does not set :proxy_command by default" do
cmd

expect(state.keys).to_not include(:proxy_command)
end

expect(state.keys).to_not include(:proxy_command)
it "sets :proxy_command if ProxyCommand is in ssh-config" do
output.concat(" ProxyCommand echo proxy\n")
cmd

expect(state).to include(:proxy_command => "echo proxy")
end
end

it "sets :proxy_command if ProxyCommand is in ssh-config" do
output.concat(" ProxyCommand echo proxy\n")
cmd
context "for WinRM-based transports" do

expect(state).to include(:proxy_command => "echo proxy")
before { allow(transport).to receive(:name).and_return("WinRM") }

it "sets :username from config" do
config[:username] = "winuser"
cmd

expect(state).to include(:username => "winuser")
end

it "sets :password from config" do
config[:password] = "mysecret"
cmd

expect(state).to include(:password => "mysecret")
end
end
end

Expand Down