vagrant-windows 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +19 -0
- data/Gemfile +5 -0
- data/README.md +78 -0
- data/Rakefile +2 -0
- data/lib/vagrant-windows/communication/winrm.rb +180 -0
- data/lib/vagrant-windows/config/windows.rb +27 -0
- data/lib/vagrant-windows/config/winrm.rb +31 -0
- data/lib/vagrant-windows/errors.rb +17 -0
- data/lib/vagrant-windows/guest/windows.rb +54 -0
- data/lib/vagrant-windows/monkey_patches/vm.rb +16 -0
- data/lib/vagrant-windows/scripts/command_alias.ps1 +23 -0
- data/lib/vagrant-windows/scripts/mount_volume.ps1.erb +43 -0
- data/lib/vagrant-windows/version.rb +3 -0
- data/lib/vagrant-windows/winrm.rb +82 -0
- data/lib/vagrant_init.rb +18 -0
- data/vagrant-windows.gemspec +21 -0
- metadata +111 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
Building a Base Box
|
|
2
|
+
===================
|
|
3
|
+
|
|
4
|
+
-Enable WinRM
|
|
5
|
+
|
|
6
|
+
```
|
|
7
|
+
winrm quickconfig -q
|
|
8
|
+
winrm set winrm/config/winrs @{MaxMemoryPerShellMB="512"}
|
|
9
|
+
winrm set winrm/config @{MaxTimeoutms="1800000"}
|
|
10
|
+
winrm set winrm/config/service @{AllowUnencrypted="true"}
|
|
11
|
+
winrm set winrm/config/service/auth @{Basic="true"}
|
|
12
|
+
```
|
|
13
|
+
- Create a vagrant user
|
|
14
|
+
- For things to work out of the box, username and password should both be vagrant
|
|
15
|
+
|
|
16
|
+
- Turn off UAC
|
|
17
|
+
- Disable Shutdown Tracker
|
|
18
|
+
|
|
19
|
+
The Vagrant File
|
|
20
|
+
================
|
|
21
|
+
|
|
22
|
+
Add the following to your Vagrantfile
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
config.vm.guest = :windows
|
|
26
|
+
|
|
27
|
+
config.vm.forward_port 3389, 3390, :name => "rdp", :auto => true
|
|
28
|
+
config.vm.forward_port 5985, 5985, :name => "winrm", :auto => true
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Example:
|
|
32
|
+
```ruby
|
|
33
|
+
Vagrant::Config.run do |config|
|
|
34
|
+
|
|
35
|
+
# Configure base box parameters
|
|
36
|
+
config.vm.box = "windows2008r2"
|
|
37
|
+
config.vm.box_url = "./windows-2008-r2.box"
|
|
38
|
+
config.vm.guest = :windows
|
|
39
|
+
|
|
40
|
+
config.vm.forward_port 3389, 3390, :name => "rdp", :auto => true
|
|
41
|
+
config.vm.forward_port 5985, 5985, :name => "winrm", :auto => true
|
|
42
|
+
|
|
43
|
+
config.vm.provision :chef_solo do |chef|
|
|
44
|
+
chef.add_recipe("your::recipe")
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
What Works?
|
|
50
|
+
===========
|
|
51
|
+
- vagrant up|hault|reload|provision
|
|
52
|
+
- Chef Vagrant Provisioner
|
|
53
|
+
|
|
54
|
+
What has not been tested
|
|
55
|
+
========================
|
|
56
|
+
- Everything Else!!!
|
|
57
|
+
- Shell and Puppet Provisioners
|
|
58
|
+
- Shell should work, though I have not vetted it yet.
|
|
59
|
+
|
|
60
|
+
What Can I do to help?
|
|
61
|
+
======================
|
|
62
|
+
1. Contribute Code (See Below)
|
|
63
|
+
2. Test Various Scenarios and file bugs for things that dont work
|
|
64
|
+
|
|
65
|
+
Contributing
|
|
66
|
+
============
|
|
67
|
+
1. Fork it.
|
|
68
|
+
2. Create a branch (git checkout -b my_feature_branch)
|
|
69
|
+
3. Commit your changes (git commit -am "Added a sweet feature")
|
|
70
|
+
4. Push to the branch (git push origin my_feature_branch)
|
|
71
|
+
5. Create a pull requst from your branch into master (Please be sure to provide enough detail for us to cipher what this change is doing)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
References and Shout Outs
|
|
75
|
+
=========================
|
|
76
|
+
Chris McClimans - Vagrant Branch (https://github.com/hh/vagrant/blob/feature/winrm/)
|
|
77
|
+
Dan Wanek - WinRM GEM (https://github.com/zenchild/WinRM)
|
|
78
|
+
+1 For being super responsive to pull requests.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
require 'timeout'
|
|
2
|
+
|
|
3
|
+
require 'log4r'
|
|
4
|
+
#require 'em-winrm'
|
|
5
|
+
require 'winrm'
|
|
6
|
+
require 'highline'
|
|
7
|
+
|
|
8
|
+
require 'vagrant/util/ansi_escape_code_remover'
|
|
9
|
+
require 'vagrant/util/file_mode'
|
|
10
|
+
require 'vagrant/util/platform'
|
|
11
|
+
require 'vagrant/util/retryable'
|
|
12
|
+
|
|
13
|
+
module Vagrant
|
|
14
|
+
module Communication
|
|
15
|
+
# Provides communication with the VM via WinRM.
|
|
16
|
+
class WinRM < Base
|
|
17
|
+
|
|
18
|
+
include Util::ANSIEscapeCodeRemover
|
|
19
|
+
include Util::Retryable
|
|
20
|
+
|
|
21
|
+
attr_reader :logger
|
|
22
|
+
attr_reader :vm
|
|
23
|
+
|
|
24
|
+
def initialize(vm)
|
|
25
|
+
@vm = vm
|
|
26
|
+
@logger = Log4r::Logger.new("vagrant::communication::winrm")
|
|
27
|
+
@co = nil
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def ready?
|
|
31
|
+
logger.debug("Checking whether WinRM is ready...")
|
|
32
|
+
|
|
33
|
+
Timeout.timeout(@vm.config.winrm.timeout) do
|
|
34
|
+
execute "hostname"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# If we reached this point then we successfully connected
|
|
38
|
+
logger.info("WinRM is ready!")
|
|
39
|
+
true
|
|
40
|
+
rescue Timeout::Error => e
|
|
41
|
+
#, Errors::SSHConnectionRefused, Net::SSH::Disconnect => e
|
|
42
|
+
# The above errors represent various reasons that WinRM may not be
|
|
43
|
+
# ready yet. Return false.
|
|
44
|
+
logger.info("WinRM not up yet: #{e.inspect}")
|
|
45
|
+
|
|
46
|
+
return false
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Wrap Sudo in execute.... One day we could integrate with UAC, but Icky
|
|
50
|
+
def sudo(command, opts=nil, &block)
|
|
51
|
+
execute(command,opts,&block)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def execute(command, opts=nil, &block)
|
|
55
|
+
|
|
56
|
+
# Connect to WinRM, giving it a few tries
|
|
57
|
+
logger.info("Connecting to WinRM: #{@vm.winrm.info[:host]}:#{@vm.winrm.info[:port]}")
|
|
58
|
+
|
|
59
|
+
opts = {
|
|
60
|
+
:error_check => true,
|
|
61
|
+
:error_class => Errors::VagrantError,
|
|
62
|
+
:error_key => :winrm_bad_exit_status,
|
|
63
|
+
:command => command,
|
|
64
|
+
:sudo => false,
|
|
65
|
+
:shell => :powershell
|
|
66
|
+
}.merge(opts || {})
|
|
67
|
+
|
|
68
|
+
# Connect via WinRM and execute the command in the shell.
|
|
69
|
+
exceptions = [HTTPClient::KeepAliveDisconnected]
|
|
70
|
+
exit_status = retryable(:tries => @vm.config.winrm.max_tries, :on => exceptions, :sleep => 10) do
|
|
71
|
+
logger.debug "WinRM Trying to connect"
|
|
72
|
+
shell_execute(command,opts[:shell], &block)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
logger.debug("#{command} EXIT STATUS #{exit_status.inspect}")
|
|
76
|
+
|
|
77
|
+
# Check for any errors
|
|
78
|
+
if opts[:error_check] && exit_status != 0
|
|
79
|
+
# The error classes expect the translation key to be _key,
|
|
80
|
+
# but that makes for an ugly configuration parameter, so we
|
|
81
|
+
# set it here from `error_key`
|
|
82
|
+
error_opts = opts.merge(:_key => opts[:error_key])
|
|
83
|
+
raise opts[:error_class], error_opts
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Return the exit status
|
|
87
|
+
exit_status
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def new_session
|
|
91
|
+
opts = {
|
|
92
|
+
:user => vm.config.winrm.username,
|
|
93
|
+
:pass => vm.config.winrm.password,
|
|
94
|
+
:host => vm.config.winrm.host,
|
|
95
|
+
:port => vm.winrm.info[:port],
|
|
96
|
+
:basic_auth_only => true
|
|
97
|
+
}.merge ({})
|
|
98
|
+
|
|
99
|
+
# create a session
|
|
100
|
+
begin
|
|
101
|
+
endpoint = "http://#{opts[:host]}:#{opts[:port]}/wsman"
|
|
102
|
+
client = ::WinRM::WinRMWebService.new(endpoint, :plaintext, opts)
|
|
103
|
+
client.set_timeout(opts[:operation_timeout]) if opts[:operation_timeout]
|
|
104
|
+
rescue ::WinRM::WinRMAuthorizationError => error
|
|
105
|
+
raise ::WinRM::WinRMAuthorizationError.new("#{error.message}@#{opts[:host]}")
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
client
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def session
|
|
112
|
+
@session ||= new_session
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def h
|
|
116
|
+
@highline ||= HighLine.new
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def print_data(data, color = :cyan)
|
|
120
|
+
if data =~ /\n/
|
|
121
|
+
data.split(/\n/).each { |d| print_data(d, color) }
|
|
122
|
+
else
|
|
123
|
+
puts "#{h.color('winrm', color)} #{data.chomp}"
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def upload(from, to)
|
|
128
|
+
file = "winrm-upload-#{rand()}"
|
|
129
|
+
file_name = (session.cmd("echo %TEMP%\\#{file}"))[:data][0][:stdout].chomp
|
|
130
|
+
session.powershell <<-EOH
|
|
131
|
+
if(Test-Path #{to})
|
|
132
|
+
{
|
|
133
|
+
rm #{to}
|
|
134
|
+
}
|
|
135
|
+
EOH
|
|
136
|
+
Base64.encode64(IO.binread(from)).gsub("\n",'').chars.to_a.each_slice(8000-file_name.size) do |chunk|
|
|
137
|
+
out = session.cmd( "echo #{chunk.join} >> \"#{file_name}\"" )
|
|
138
|
+
end
|
|
139
|
+
execute "mkdir [System.IO.Path]::GetDirectoryName(\"#{to}\")"
|
|
140
|
+
execute <<-EOH
|
|
141
|
+
$base64_string = Get-Content \"#{file_name}\"
|
|
142
|
+
$bytes = [System.Convert]::FromBase64String($base64_string)
|
|
143
|
+
$new_file = [System.IO.Path]::GetFullPath(\"#{to}\")
|
|
144
|
+
[System.IO.File]::WriteAllBytes($new_file,$bytes)
|
|
145
|
+
EOH
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
protected
|
|
149
|
+
|
|
150
|
+
# Executes the command on an SSH connection within a login shell.
|
|
151
|
+
def shell_execute(command,shell = :powershell)
|
|
152
|
+
logger.info("Execute: #{command}")
|
|
153
|
+
exit_status = nil
|
|
154
|
+
|
|
155
|
+
if shell.eql? :cmd
|
|
156
|
+
output = session.cmd(command) do |out,error|
|
|
157
|
+
print_data(out) if out
|
|
158
|
+
print_data(error) if error
|
|
159
|
+
end
|
|
160
|
+
elsif shell.eql? :powershell
|
|
161
|
+
new_command = File.read(File.expand_path("#{File.dirname(__FILE__)}/../scripts/command_alias.ps1"))
|
|
162
|
+
new_command << "\r\n"
|
|
163
|
+
new_command << command
|
|
164
|
+
output = session.powershell(new_command) do |out,error|
|
|
165
|
+
print_data(out) if out
|
|
166
|
+
print_data(error) if error
|
|
167
|
+
end
|
|
168
|
+
else
|
|
169
|
+
raise Vagrant::Errors::WinRMInvalidShell, "#{shell} is not a valid type of shell"
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
exit_status = output[:exitcode]
|
|
173
|
+
logger.debug exit_status.inspect
|
|
174
|
+
|
|
175
|
+
# Return the final exit status
|
|
176
|
+
return exit_status
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Vagrant
|
|
2
|
+
module Config
|
|
3
|
+
class Windows < Vagrant::Config::Base
|
|
4
|
+
attr_accessor :winrm_user
|
|
5
|
+
attr_accessor :winrm_password
|
|
6
|
+
attr_accessor :halt_timeout
|
|
7
|
+
attr_accessor :halt_check_interval
|
|
8
|
+
attr_accessor :device
|
|
9
|
+
|
|
10
|
+
def initialize
|
|
11
|
+
@winrm_user = 'vagrant'
|
|
12
|
+
@winrm_password = 'vagrant'
|
|
13
|
+
@halt_timeout = 30
|
|
14
|
+
@halt_check_interval = 1
|
|
15
|
+
@device = "e1000g"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def validate(env, errors)
|
|
19
|
+
[ :winrm_user, :winrm_password].each do |field|
|
|
20
|
+
errors.add(I18n.t("vagrant.config.common.error_empty", :field => field)) if !instance_variable_get("@#{field}".to_sym)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
Vagrant.config_keys.register(:windows) { Vagrant::Config::Windows }
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Vagrant
|
|
2
|
+
module Config
|
|
3
|
+
class WinRM < Vagrant::Config::Base
|
|
4
|
+
attr_accessor :username
|
|
5
|
+
attr_accessor :password
|
|
6
|
+
attr_accessor :host
|
|
7
|
+
attr_accessor :port
|
|
8
|
+
attr_accessor :guest_port
|
|
9
|
+
attr_accessor :max_tries
|
|
10
|
+
attr_accessor :timeout
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
@username = "vagrant"
|
|
14
|
+
@password = "vagrant"
|
|
15
|
+
@guest_port = 5985
|
|
16
|
+
@host = "localhost"
|
|
17
|
+
@max_tries = 12
|
|
18
|
+
@timeout = 30
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def validate(env, errors)
|
|
22
|
+
[:username, :password, :host, :max_tries, :timeout].each do |field|
|
|
23
|
+
errors.add(I18n.t("vagrant.config.common.error_empty", :field => field)) if !instance_variable_get("@#{field}".to_sym)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
Vagrant.config_keys.register(:winrm) { Vagrant::Config::WinRM }
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Vagrant
|
|
2
|
+
module Errors
|
|
3
|
+
class WinRMPortNotDetected < VagrantError
|
|
4
|
+
status_code(550)
|
|
5
|
+
error_key(:winrm_port_not_detected)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
class WinRMInvalidShell < VagrantError
|
|
9
|
+
status_code(551)
|
|
10
|
+
error_key(:winrm_invalid_shell)
|
|
11
|
+
end
|
|
12
|
+
class WinRMTransferError < VagrantError
|
|
13
|
+
status_code(552)
|
|
14
|
+
error_key(:winrm_upload_error)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module Vagrant
|
|
2
|
+
module Guest
|
|
3
|
+
# A general Vagrant system implementation for "windows".
|
|
4
|
+
#
|
|
5
|
+
# Contributed by Chris McClimans <chris@hippiehacker.org>
|
|
6
|
+
class Windows < Base
|
|
7
|
+
# A custom config class which will be made accessible via `config.windows`
|
|
8
|
+
# Here for whenever it may be used.
|
|
9
|
+
class WindowsError < Errors::VagrantError
|
|
10
|
+
error_namespace("vagrant.guest.windows")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def change_host_name(name)
|
|
14
|
+
#### on windows, renaming a computer seems to require a reboot
|
|
15
|
+
vm.channel.execute("wmic computersystem where name=\"%COMPUTERNAME%\" call rename name=\"#{name}\"")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def halt
|
|
19
|
+
@vm.channel.execute("shutdown /s /t 1 /c \"Vagrant Halt\" /f /d p:4:1")
|
|
20
|
+
|
|
21
|
+
# Wait until the VM's state is actually powered off. If this doesn't
|
|
22
|
+
# occur within a reasonable amount of time (15 seconds by default),
|
|
23
|
+
# then simply return and allow Vagrant to kill the machine.
|
|
24
|
+
count = 0
|
|
25
|
+
while @vm.state != :poweroff
|
|
26
|
+
count += 1
|
|
27
|
+
|
|
28
|
+
return if count >= @vm.config.linux.halt_timeout
|
|
29
|
+
sleep @vm.config.windows.halt_check_interval
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def mount_shared_folder(name, guestpath, options)
|
|
34
|
+
mount_script = TemplateRenderer.render(File.expand_path("#{File.dirname(__FILE__)}/../scripts/mount_volume.ps1"),
|
|
35
|
+
:options => {:mount_point => guestpath, :name => name})
|
|
36
|
+
|
|
37
|
+
@vm.channel.execute(mount_script,{:shell => :powershell})
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def windows_path(path)
|
|
41
|
+
p = ''
|
|
42
|
+
if path =~ /^\//
|
|
43
|
+
p << 'C:\\'
|
|
44
|
+
end
|
|
45
|
+
p << path
|
|
46
|
+
p.gsub! /\//, "\\"
|
|
47
|
+
p.gsub /\\\\{0,}/, "\\"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
Vagrant.guests.register(:windows) { Vagrant::Guest::Windows }
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Vagrant
|
|
2
|
+
class VM
|
|
3
|
+
def winrm
|
|
4
|
+
@winrm ||= WinRM.new(self)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def channel
|
|
8
|
+
if @guest.class.eql? Vagrant::Guest::Windows
|
|
9
|
+
@channel ||= Communication::WinRM.new(self)
|
|
10
|
+
else
|
|
11
|
+
@channel ||= Communication::SSH.new(self)
|
|
12
|
+
end
|
|
13
|
+
@channel
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
function which {
|
|
2
|
+
$command = [Array](Get-Command $args[0] -errorAction continue)
|
|
3
|
+
write-host $command[0].Definition
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
function test ([Switch] $d, [String] $path) {
|
|
7
|
+
Resolve-Path $path| Out-Null;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function chown {
|
|
11
|
+
exit 0
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function mkdir ([Switch] $p, [String] $path)
|
|
15
|
+
{
|
|
16
|
+
if(Test-Path $path)
|
|
17
|
+
{
|
|
18
|
+
exit 0
|
|
19
|
+
} else {
|
|
20
|
+
New-Item $p -Type Directory -Force | Out-Null
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
|
|
2
|
+
function Test-ReparsePoint([string]$path) {
|
|
3
|
+
$file = Get-Item $path -Force -ea 0
|
|
4
|
+
return [bool]($file.Attributes -band [IO.FileAttributes]::ReparsePoint)
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
$MountPoint = [System.IO.Path]::GetFullPath("<%= options[:mount_point] %>")
|
|
8
|
+
$ShareName = "<%= options[:name] %>"
|
|
9
|
+
|
|
10
|
+
Write-Host "Attempting to mount $ShareName to $MountPoint"
|
|
11
|
+
if( (Test-Path "$MountPoint") -and (Test-ReparsePoint "$MountPoint") )
|
|
12
|
+
{
|
|
13
|
+
Write-Host "Junction already exists, so I will delete it"
|
|
14
|
+
# Powershell refuses to delete junctions, oh well use cmd
|
|
15
|
+
cmd /c rd "$MountPoint"
|
|
16
|
+
|
|
17
|
+
if ( $LASTEXITCODE -ne 0 )
|
|
18
|
+
{
|
|
19
|
+
Write-Error "Failed to delete symbolic link at $MountPoint"
|
|
20
|
+
exit 1
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
}
|
|
24
|
+
elseif(Test-Path $MountPoint)
|
|
25
|
+
{
|
|
26
|
+
Write-Host "Mount point already exists and is not a symbolic link"
|
|
27
|
+
exit 1
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
$BaseDirectory = [System.IO.Path]::GetDirectoryName($MountPoint)
|
|
31
|
+
|
|
32
|
+
if (-not (Test-Path $BaseDirectory))
|
|
33
|
+
{
|
|
34
|
+
Write-Host "Creating parent directory for mount point"
|
|
35
|
+
mkdir $BaseDirectory
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
cmd /c mklink /D "$MountPoint" "\\vboxsrv\$ShareName"
|
|
39
|
+
|
|
40
|
+
if ( $LASTEXITCODE -ne 0 )
|
|
41
|
+
{
|
|
42
|
+
exit 1
|
|
43
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
require 'log4r'
|
|
2
|
+
#require 'em-winrm'
|
|
3
|
+
|
|
4
|
+
module Vagrant
|
|
5
|
+
# Manages WINRM access to a specific environment. Allows an environment to
|
|
6
|
+
# run commands, upload files, and check if a host is up.
|
|
7
|
+
class WinRM
|
|
8
|
+
include Util::SafeExec
|
|
9
|
+
|
|
10
|
+
def initialize(vm)
|
|
11
|
+
@vm = vm
|
|
12
|
+
@logger = Log4r::Logger.new("vagrant::winrm")
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Returns a hash of information necessary for accessing this
|
|
16
|
+
# virtual machine via WINRM.
|
|
17
|
+
#
|
|
18
|
+
# @return [Hash]
|
|
19
|
+
def info
|
|
20
|
+
results = {
|
|
21
|
+
:host => @vm.config.winrm.host,
|
|
22
|
+
:port => @vm.config.winrm.port || @vm.driver.ssh_port(@vm.config.winrm.guest_port),
|
|
23
|
+
:username => @vm.config.winrm.username
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
# This can happen if no port is set and for some reason Vagrant
|
|
27
|
+
# can't detect an SSH port.
|
|
28
|
+
raise Errors::WinRMPortNotDetected if !results[:port]
|
|
29
|
+
|
|
30
|
+
# Return the results
|
|
31
|
+
return results
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Checks if this environment's machine is up (i.e. responding to WINRM).
|
|
35
|
+
#
|
|
36
|
+
# @return [Boolean]
|
|
37
|
+
def up?
|
|
38
|
+
# We have to determine the port outside of the block since it uses
|
|
39
|
+
# API calls which can only be used from the main thread in JRuby on
|
|
40
|
+
# Windows
|
|
41
|
+
ssh_port = port
|
|
42
|
+
|
|
43
|
+
require 'timeout'
|
|
44
|
+
Timeout.timeout(@env.config.ssh.timeout) do
|
|
45
|
+
execute 'hostname'
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
true
|
|
49
|
+
rescue Timeout::Error, Errno::ECONNREFUSED
|
|
50
|
+
return false
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Returns the port which is either given in the options hash or taken from
|
|
54
|
+
# the config by finding it in the forwarded ports hash based on the
|
|
55
|
+
# `config.ssh.forwarded_port_key`.
|
|
56
|
+
def port(opts={})
|
|
57
|
+
# Check if port was specified in options hash
|
|
58
|
+
return opts[:port] if opts[:port]
|
|
59
|
+
|
|
60
|
+
# Check if a port was specified in the config
|
|
61
|
+
return @env.config.winrm.port if @env.config.winrm.port
|
|
62
|
+
|
|
63
|
+
# Check if we have an SSH forwarded port
|
|
64
|
+
pnum_by_name = nil
|
|
65
|
+
pnum_by_destination = nil
|
|
66
|
+
@logger.info("Looking for winrm port: #{opts}")
|
|
67
|
+
@logger.info("Looking for winrm port: #{env.config.winrm.inspect}")
|
|
68
|
+
|
|
69
|
+
env.vm.vm.network_adapters.each do |na|
|
|
70
|
+
# Look for the port number by destination...
|
|
71
|
+
pnum_by_destination = na.nat_driver.forwarded_ports.detect do |fp|
|
|
72
|
+
fp.guestport == env.config.winrm.guest_port
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
return pnum_by_destination.hostport if pnum_by_destination
|
|
77
|
+
|
|
78
|
+
# This should NEVER happen.
|
|
79
|
+
raise Errors::WinRMPortNotDetected
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
data/lib/vagrant_init.rb
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#Add Windows Guest Defintion
|
|
2
|
+
require 'vagrant-windows/guest/windows'
|
|
3
|
+
|
|
4
|
+
#Add Configuration Items
|
|
5
|
+
require 'vagrant-windows/config/windows'
|
|
6
|
+
require 'vagrant-windows/config/winrm'
|
|
7
|
+
|
|
8
|
+
# Add WinRM Communication Channel
|
|
9
|
+
require 'vagrant-windows/communication/winrm'
|
|
10
|
+
|
|
11
|
+
#Monkey Patch the VM object to support multiple channels
|
|
12
|
+
require 'vagrant-windows/monkey_patches/vm'
|
|
13
|
+
|
|
14
|
+
require 'vagrant-windows/winrm'
|
|
15
|
+
|
|
16
|
+
#Errors are good
|
|
17
|
+
require 'vagrant-windows/errors'
|
|
18
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
require File.expand_path('../lib/vagrant-windows/version', __FILE__)
|
|
3
|
+
|
|
4
|
+
Gem::Specification.new do |gem|
|
|
5
|
+
gem.authors = ["Paul Morton"]
|
|
6
|
+
gem.email = ["pmorton@biaprotect.com"]
|
|
7
|
+
gem.description = %q{Windows Guest Support for Vagrant}
|
|
8
|
+
gem.summary = %q{A small gem that adds windows guest support to vagrant, uses WinRM as the Communication Channel}
|
|
9
|
+
gem.homepage = ""
|
|
10
|
+
|
|
11
|
+
gem.files = `git ls-files`.split($\)
|
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
|
14
|
+
gem.name = "vagrant-windows"
|
|
15
|
+
gem.require_paths = ["lib"]
|
|
16
|
+
gem.version = VagrantWindows::VERSION
|
|
17
|
+
|
|
18
|
+
gem.add_runtime_dependency "winrm", "~> 1.1.1"
|
|
19
|
+
gem.add_runtime_dependency 'vagrant', "~> 1.0.3"
|
|
20
|
+
gem.add_runtime_dependency 'highline'
|
|
21
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: vagrant-windows
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Paul Morton
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2012-06-04 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: winrm
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ~>
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: 1.1.1
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ~>
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: 1.1.1
|
|
30
|
+
- !ruby/object:Gem::Dependency
|
|
31
|
+
name: vagrant
|
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
|
33
|
+
none: false
|
|
34
|
+
requirements:
|
|
35
|
+
- - ~>
|
|
36
|
+
- !ruby/object:Gem::Version
|
|
37
|
+
version: 1.0.3
|
|
38
|
+
type: :runtime
|
|
39
|
+
prerelease: false
|
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
41
|
+
none: false
|
|
42
|
+
requirements:
|
|
43
|
+
- - ~>
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: 1.0.3
|
|
46
|
+
- !ruby/object:Gem::Dependency
|
|
47
|
+
name: highline
|
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
|
49
|
+
none: false
|
|
50
|
+
requirements:
|
|
51
|
+
- - ! '>='
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
54
|
+
type: :runtime
|
|
55
|
+
prerelease: false
|
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
57
|
+
none: false
|
|
58
|
+
requirements:
|
|
59
|
+
- - ! '>='
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
description: Windows Guest Support for Vagrant
|
|
63
|
+
email:
|
|
64
|
+
- pmorton@biaprotect.com
|
|
65
|
+
executables: []
|
|
66
|
+
extensions: []
|
|
67
|
+
extra_rdoc_files: []
|
|
68
|
+
files:
|
|
69
|
+
- .gitignore
|
|
70
|
+
- Gemfile
|
|
71
|
+
- Gemfile.lock
|
|
72
|
+
- README.md
|
|
73
|
+
- Rakefile
|
|
74
|
+
- lib/vagrant-windows/communication/winrm.rb
|
|
75
|
+
- lib/vagrant-windows/config/windows.rb
|
|
76
|
+
- lib/vagrant-windows/config/winrm.rb
|
|
77
|
+
- lib/vagrant-windows/errors.rb
|
|
78
|
+
- lib/vagrant-windows/guest/windows.rb
|
|
79
|
+
- lib/vagrant-windows/monkey_patches/vm.rb
|
|
80
|
+
- lib/vagrant-windows/scripts/command_alias.ps1
|
|
81
|
+
- lib/vagrant-windows/scripts/mount_volume.ps1.erb
|
|
82
|
+
- lib/vagrant-windows/version.rb
|
|
83
|
+
- lib/vagrant-windows/winrm.rb
|
|
84
|
+
- lib/vagrant_init.rb
|
|
85
|
+
- vagrant-windows.gemspec
|
|
86
|
+
homepage: ''
|
|
87
|
+
licenses: []
|
|
88
|
+
post_install_message:
|
|
89
|
+
rdoc_options: []
|
|
90
|
+
require_paths:
|
|
91
|
+
- lib
|
|
92
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
93
|
+
none: false
|
|
94
|
+
requirements:
|
|
95
|
+
- - ! '>='
|
|
96
|
+
- !ruby/object:Gem::Version
|
|
97
|
+
version: '0'
|
|
98
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
99
|
+
none: false
|
|
100
|
+
requirements:
|
|
101
|
+
- - ! '>='
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '0'
|
|
104
|
+
requirements: []
|
|
105
|
+
rubyforge_project:
|
|
106
|
+
rubygems_version: 1.8.24
|
|
107
|
+
signing_key:
|
|
108
|
+
specification_version: 3
|
|
109
|
+
summary: A small gem that adds windows guest support to vagrant, uses WinRM as the
|
|
110
|
+
Communication Channel
|
|
111
|
+
test_files: []
|