vagrant-windows 1.0.3 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.travis.yml +5 -0
- data/Gemfile +1 -1
- data/README.md +77 -20
- data/Rakefile +14 -4
- data/lib/vagrant-windows/communication/guestnetwork.rb +133 -0
- data/lib/vagrant-windows/communication/winrmcommunicator.rb +56 -151
- data/lib/vagrant-windows/communication/winrmfinder.rb +45 -0
- data/lib/vagrant-windows/communication/winrmshell.rb +141 -0
- data/lib/vagrant-windows/config/windows.rb +4 -0
- data/lib/vagrant-windows/config/winrm.rb +1 -1
- data/lib/vagrant-windows/guest/cap/change_host_name.rb +14 -0
- data/lib/vagrant-windows/guest/cap/configure_networks.rb +69 -0
- data/lib/vagrant-windows/guest/cap/halt.rb +22 -0
- data/lib/vagrant-windows/guest/cap/mount_virtualbox_shared_folder.rb +17 -0
- data/lib/vagrant-windows/guest/cap/mount_vmware_shared_folder.rb +15 -0
- data/lib/vagrant-windows/guest/windows.rb +46 -77
- data/lib/vagrant-windows/helper.rb +6 -0
- data/lib/vagrant-windows/monkey_patches/{machine.rb → lib/vagrant/machine.rb} +7 -0
- data/lib/vagrant-windows/monkey_patches/plugins/providers/virtualbox/action/share_folders.rb +44 -0
- data/lib/vagrant-windows/monkey_patches/{vbox_42_driver.rb → plugins/providers/virtualbox/driver/version_4_2.rb} +0 -0
- data/lib/vagrant-windows/monkey_patches/plugins/provisioners/chef/provisioner/chef_client.rb +1 -0
- data/lib/vagrant-windows/monkey_patches/plugins/provisioners/chef/provisioner/chef_solo.rb +106 -0
- data/lib/vagrant-windows/monkey_patches/{puppet.rb → plugins/provisioners/puppet/provisioner/puppet.rb} +5 -4
- data/lib/vagrant-windows/monkey_patches/plugins/provisioners/puppet/provisioner/puppet_server.rb +1 -0
- data/lib/vagrant-windows/monkey_patches/{provisioner.rb → plugins/provisioners/shell/provisioner.rb} +4 -4
- data/lib/vagrant-windows/plugin.rb +54 -27
- data/lib/vagrant-windows/scripts/cheftask.ps1.erb +47 -0
- data/lib/vagrant-windows/scripts/cheftask.xml.erb +45 -0
- data/lib/vagrant-windows/scripts/cheftaskrun.ps1.erb +16 -0
- data/lib/vagrant-windows/scripts/command_alias.ps1 +4 -0
- data/lib/vagrant-windows/scripts/{mount_volume.ps1.erb → mount_volume.virtualbox.ps1.erb} +1 -1
- data/lib/vagrant-windows/scripts/mount_volume.vmware.ps1.erb +49 -0
- data/lib/vagrant-windows/scripts/set_work_network.ps1 +6 -0
- data/lib/vagrant-windows/scripts/winrs_v3_get_adapters.ps1 +11 -0
- data/lib/vagrant-windows/version.rb +1 -1
- data/spec/spec_helper.rb +14 -0
- data/spec/vagrant-windows/config_spec.rb +3 -4
- data/spec/vagrant-windows/guestnetwork_spec.rb +47 -0
- data/spec/vagrant-windows/helper_spec.rb +14 -3
- data/spec/vagrant-windows/winrmcommunicator_spec.rb +26 -0
- data/vagrant-windows.gemspec +33 -2
- metadata +100 -55
- data/lib/vagrant-windows/monkey_patches/chef_solo.rb +0 -61
- data/lib/vagrant-windows/scripts/ps_runas.ps1.erb +0 -56
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cecfc851c351d99894540e03b595c9ed93fb313b
|
4
|
+
data.tar.gz: 325c6d920df52dc61f4db48e64337b88480a1b0d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c5d93cd182875294ee9c50911b272363752039d8ab1ccae5c620291b109eb7c04a3ec8073901982e64fa040b04678197936fc8f2fe97d925ebb71fb8c230c438
|
7
|
+
data.tar.gz: 9932265ce43b14f7b942146291e1696d861c2070d8b79b147bda0b02bc4e41ac486b8996e20fac232802ddea0b083f276e2dddd7f7692cd5e49a711033fc2582
|
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/Gemfile
CHANGED
@@ -7,5 +7,5 @@ group :development do
|
|
7
7
|
# We depend on Vagrant for development, but we don't add it as a
|
8
8
|
# gem dependency because we expect to be installed within the
|
9
9
|
# Vagrant environment itself using `vagrant plugin`.
|
10
|
-
gem "vagrant", :git => "git://github.com/mitchellh/vagrant.git", :tag => 'v1.
|
10
|
+
gem "vagrant", :git => "git://github.com/mitchellh/vagrant.git", :tag => 'v1.2.2'
|
11
11
|
end
|
data/README.md
CHANGED
@@ -1,9 +1,19 @@
|
|
1
1
|
Installing Vagrant-Windows
|
2
2
|
==========================
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
For Vagrant 1.1.x and 1.2.x execute `vagrant plugin install vagrant-windows`.
|
5
|
+
For Vagrant 1.0.x execute `vagrant plugin install vagrant-windows --plugin-version 0.1.2`.
|
6
|
+
|
7
|
+
### Installing Vagrant-Windows From Source
|
8
|
+
If you want to install from source, use the following method (this would be for 1.2.0):
|
9
|
+
|
10
|
+
```
|
11
|
+
bundle install
|
12
|
+
bundle exec rake
|
13
|
+
vagrant plugin install pkg/vagrant-windows-1.2.0.gem
|
14
|
+
```
|
15
|
+
|
16
|
+
Keep in mind you should have Ruby 1.9.3 and Ruby DevKit installed. Check out the following gist that can get you what you need (from blank system to fully ready): [Install Vagrant Windows Plugin From Source Gist](https://gist.github.com/ferventcoder/6251225).
|
7
17
|
|
8
18
|
Supported Guest Operating Systems (Your VM)
|
9
19
|
===========================================
|
@@ -20,7 +30,24 @@ Building a Base Box
|
|
20
30
|
|
21
31
|
All Windows Machines
|
22
32
|
--------------------
|
23
|
-
|
33
|
+
#### Prerequisites
|
34
|
+
|
35
|
+
Box setup:
|
36
|
+
|
37
|
+
- Create a vagrant user, for things to work out of the box username and password should both be "vagrant".
|
38
|
+
- Turn off UAC (Msconfig)
|
39
|
+
- Disable complex passwords
|
40
|
+
|
41
|
+
Prior to enabling WinRM, you must ensure the following services are enabled:
|
42
|
+
|
43
|
+
- Base Filtering Engine
|
44
|
+
- Remote Procedure Call (RPC)
|
45
|
+
- DCOM Server Process Launcher
|
46
|
+
- RPC Endpoint Mapper
|
47
|
+
- Windows Firewall
|
48
|
+
- Windows Remote Management (WS-Management)
|
49
|
+
|
50
|
+
#### Enable WinRM
|
24
51
|
```
|
25
52
|
winrm quickconfig -q
|
26
53
|
winrm set winrm/config/winrs @{MaxMemoryPerShellMB="512"}
|
@@ -28,12 +55,21 @@ All Windows Machines
|
|
28
55
|
winrm set winrm/config/service @{AllowUnencrypted="true"}
|
29
56
|
winrm set winrm/config/service/auth @{Basic="true"}
|
30
57
|
```
|
31
|
-
|
32
|
-
|
33
|
-
|
58
|
+
* note
|
59
|
+
If you want to run the winrm commands from PowerShell you need to put ```@{MaxMemoryPerShellMB="512"}``` etc in single quotes:
|
60
|
+
|
61
|
+
```
|
62
|
+
winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="512"}'
|
63
|
+
```
|
64
|
+
|
65
|
+
#### Last steps
|
66
|
+
|
67
|
+
- Optional: Start WinRM a few minutes faster by running: "sc config WinRM start= auto" (default is delayed-auto)
|
68
|
+
- _Note:_ When you use the `winrm` command line tool it will always ask to set the startup to Delayed, so you may find yourself performing this a few times.
|
69
|
+
|
34
70
|
|
35
|
-
Servers
|
36
|
-
|
71
|
+
Windows 2008/2012 Servers (except Core)
|
72
|
+
---------------------------------------
|
37
73
|
- [Disable Shutdown Tracker](http://www.jppinto.com/2010/01/how-to-disable-the-shutdown-event-tracker-in-server-20032008/)
|
38
74
|
- [Disable "Server Manager" Starting at login](http://www.elmajdal.net/win2k8/How_to_Turn_Off_The_Automatic_Display_of_Server_Manager_At_logon.aspx)
|
39
75
|
|
@@ -44,7 +80,7 @@ Add the following to your Vagrantfile
|
|
44
80
|
|
45
81
|
```ruby
|
46
82
|
config.vm.guest = :windows
|
47
|
-
config.windows.halt_timeout =
|
83
|
+
config.windows.halt_timeout = 25
|
48
84
|
config.winrm.username = "vagrant"
|
49
85
|
config.winrm.password = "vagrant"
|
50
86
|
config.vm.network :forwarded_port, guest: 5985, host: 5985
|
@@ -55,7 +91,7 @@ Example:
|
|
55
91
|
Vagrant.configure("2") do |config|
|
56
92
|
|
57
93
|
# Max time to wait for the guest to shutdown
|
58
|
-
config.windows.halt_timeout =
|
94
|
+
config.windows.halt_timeout = 25
|
59
95
|
|
60
96
|
# Admin user name and password
|
61
97
|
config.winrm.username = "vagrant"
|
@@ -77,12 +113,13 @@ Available Config Parameters:
|
|
77
113
|
|
78
114
|
* ```config.windows.halt_timeout``` - How long Vagrant should wait for the guest to shutdown before forcing exit, defaults to 30 seconds
|
79
115
|
* ```config.windows.halt_check_interval``` - How often Vagrant should check if the system has shutdown, defaults to 1 second
|
116
|
+
* ```config.windows.set_work_network``` - Force network adapters to "Work Network". Useful for Win7 guests using private networking.
|
80
117
|
* ```config.winrm.username``` - The Windows guest admin user name, defaults to vagrant.
|
81
118
|
* ```config.winrm.password``` - The above's password, defaults to vagrant.
|
82
119
|
* ```config.winrm.host``` - The IP of the guest, but because we use NAT with port forwarding this defaults to localhost.
|
83
120
|
* ```config.winrm.guest_port``` - The guest's WinRM port, defaults to 5985.
|
84
121
|
* ```config.winrm.port``` - The WinRM port on the host, defaults to 5985. You might need to change this if your hosts is also Windows.
|
85
|
-
* ```config.winrm.max_tries``` - The number of retries to connect to WinRM, defaults to
|
122
|
+
* ```config.winrm.max_tries``` - The number of retries to connect to WinRM, defaults to 20.
|
86
123
|
* ```config.winrm.timeout``` - The max number of seconds to wait for a WinRM response, defaults to 1800 seconds.
|
87
124
|
|
88
125
|
Note - You need to ensure you specify a config.windows and a config.winrm in your Vagrantfile. Currently there's a problem where
|
@@ -99,8 +136,7 @@ What Works?
|
|
99
136
|
TODOs
|
100
137
|
=========
|
101
138
|
1. Test it! We need to test on more hosts, guests, and VBox versions. Help wanted.
|
102
|
-
2.
|
103
|
-
3. Chef-Client support.
|
139
|
+
2. Chef-Client support.
|
104
140
|
3. Unit tests.
|
105
141
|
4. Better docs.
|
106
142
|
|
@@ -142,7 +178,7 @@ Contributing
|
|
142
178
|
4. Push to the branch (git push origin my_feature_branch)
|
143
179
|
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)
|
144
180
|
|
145
|
-
|
181
|
+
Development
|
146
182
|
=============
|
147
183
|
Clone this repository and use [Bundler](http://gembundler.com) to get the dependencies:
|
148
184
|
|
@@ -153,15 +189,32 @@ $ bundle install
|
|
153
189
|
Once you have the dependencies, you can run the tests with `rake`:
|
154
190
|
|
155
191
|
```
|
156
|
-
$ rake spec
|
192
|
+
$ bundle exec rake spec
|
157
193
|
```
|
158
194
|
|
195
|
+
If those pass, you're ready to start developing the plugin. You can test
|
196
|
+
the plugin without installing it into your Vagrant environment by just
|
197
|
+
creating a [Vagrantfile](http://docs.vagrantup.com/v2/plugins/packaging.html)
|
198
|
+
in the top level of this directory (it is gitignored) that uses it, and
|
199
|
+
use bundler to execute Vagrant:
|
200
|
+
|
201
|
+
```
|
202
|
+
$ bundle exec vagrant up
|
203
|
+
```
|
204
|
+
|
205
|
+
|
159
206
|
References and Shout Outs
|
160
207
|
=========================
|
161
208
|
- Chris McClimans - Vagrant Branch (https://github.com/hh/vagrant/blob/feature/winrm/)
|
162
209
|
- Dan Wanek - WinRM GEM (https://github.com/zenchild/WinRM)
|
163
210
|
- +1 For being super responsive to pull requests.
|
164
|
-
|
211
|
+
- Mike Griffen - Added first vagrant-windows unit tests and updated readme
|
212
|
+
- Geronimo Orozco - Shell provisioner support
|
213
|
+
- David Cournapeau - Added config.windows.set_work_network option
|
214
|
+
- keiths-osc - Fixed Vagrant 1.2 shared folder action
|
215
|
+
- Rob Reynolds - Updated readme installation and box configuration notes
|
216
|
+
- stonith - Updated readme winrm config notes
|
217
|
+
- wenns - Updated readme to advise against forwarding RDP
|
165
218
|
|
166
219
|
Changelog
|
167
220
|
=========
|
@@ -188,8 +241,12 @@ Changelog
|
|
188
241
|
|
189
242
|
1.0.3
|
190
243
|
|
191
|
-
- Added vagrant shell provisioner.
|
192
|
-
The built-in shell provisioner tried to chmod the target script which doesn't make sense on windows.
|
193
|
-
|
244
|
+
- Added vagrant shell provisioner. The built-in shell provisioner tried to chmod the target script which doesn't make sense on windows.
|
194
245
|
- Can now run the vagrant-windows plugin via bundle exec instead of vagrant plugin install (for plugin dev).The vagrant src root finding logic didn't work from a bundle, but the native Vagrant src root does.
|
195
246
|
- Readme fixes/updates.
|
247
|
+
|
248
|
+
1.2.0
|
249
|
+
|
250
|
+
- Converted to Vagrant 1.2.x plugin architecture.
|
251
|
+
- Various networking fixes.
|
252
|
+
- Chef provisioner runs through the Windows task scheduler instead of ps_runas power shell script.
|
data/Rakefile
CHANGED
@@ -8,8 +8,18 @@ Dir.chdir(File.expand_path("../", __FILE__))
|
|
8
8
|
# For gem creation and bundling
|
9
9
|
require "bundler/gem_tasks"
|
10
10
|
|
11
|
-
#
|
12
|
-
RSpec::Core::RakeTask.new
|
11
|
+
# Run the unit test suite
|
12
|
+
RSpec::Core::RakeTask.new do |task|
|
13
|
+
task.pattern = "spec/**/*_spec.rb"
|
14
|
+
task.rspec_opts = [ '--color', '-f documentation' ]
|
15
|
+
task.rspec_opts << '-tunit'
|
16
|
+
end
|
13
17
|
|
14
|
-
#
|
15
|
-
|
18
|
+
# Run the integration test suite
|
19
|
+
RSpec::Core::RakeTask.new(:integration) do |task|
|
20
|
+
task.pattern = "spec/**/*_spec.rb"
|
21
|
+
task.rspec_opts = [ '--color', '-f documentation' ]
|
22
|
+
end
|
23
|
+
|
24
|
+
# Default task is to run tests
|
25
|
+
task :default => "spec"
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
require_relative '../../vagrant-windows'
|
3
|
+
require_relative '../communication/winrmshell'
|
4
|
+
require_relative '../errors'
|
5
|
+
|
6
|
+
module VagrantWindows
|
7
|
+
module Communication
|
8
|
+
|
9
|
+
# Manages the remote Windows guest network
|
10
|
+
class GuestNetwork
|
11
|
+
|
12
|
+
PS_GET_WSMAN_VER = '((test-wsman).productversion.split(" ") | select -last 1).split("\.")[0]'
|
13
|
+
WQL_NET_ADAPTERS_V2 = 'SELECT * FROM Win32_NetworkAdapter WHERE MACAddress IS NOT NULL'
|
14
|
+
|
15
|
+
attr_reader :logger
|
16
|
+
attr_reader :winrmshell
|
17
|
+
|
18
|
+
def initialize(winrmshell)
|
19
|
+
@logger = Log4r::Logger.new("vagrant_windows::communication::winrmshell")
|
20
|
+
@logger.debug("initializing WinRMShell")
|
21
|
+
@winrmshell = winrmshell
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns an array of all NICs on the guest. Each array entry is a
|
25
|
+
# Hash of the NICs properties.
|
26
|
+
#
|
27
|
+
# @return [Array]
|
28
|
+
def network_adapters()
|
29
|
+
wsman_version() == 2? network_adapters_v2_winrm() : network_adapters_v3_winrm()
|
30
|
+
end
|
31
|
+
|
32
|
+
# Checks to see if the specified NIC is currently configured for DHCP.
|
33
|
+
#
|
34
|
+
# @return [Boolean]
|
35
|
+
def is_dhcp_enabled(nic_index)
|
36
|
+
has_dhcp_enabled = false
|
37
|
+
cmd = "Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter \"Index=#{nic_index} and DHCPEnabled=True\""
|
38
|
+
@winrmshell.powershell(cmd) do |type, line|
|
39
|
+
has_dhcp_enabled = !line.nil?
|
40
|
+
end
|
41
|
+
@logger.debug("NIC #{nic_index} has DHCP enabled: #{has_dhcp_enabled}")
|
42
|
+
has_dhcp_enabled
|
43
|
+
end
|
44
|
+
|
45
|
+
# Configures the specified interface for DHCP
|
46
|
+
#
|
47
|
+
# @param [Integer] The interface index.
|
48
|
+
# @param [String] The unique name of the NIC, such as 'Local Area Connection'.
|
49
|
+
def configure_dhcp_interface(nic_index, net_connection_id)
|
50
|
+
@logger.info("Configuring NIC #{net_connection_id} for DHCP")
|
51
|
+
if !is_dhcp_enabled(nic_index)
|
52
|
+
netsh = "netsh interface ip set address \"#{net_connection_id}\" dhcp"
|
53
|
+
@winrmshell.powershell(netsh)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Configures the specified interface using a static address
|
58
|
+
#
|
59
|
+
# @param [Integer] The interface index.
|
60
|
+
# @param [String] The unique name of the NIC, such as 'Local Area Connection'.
|
61
|
+
# @param [String] The static IP address to assign to the specified NIC.
|
62
|
+
# @param [String] The network mask to use with the static IP.
|
63
|
+
def configure_static_interface(nic_index, net_connection_id, ip, netmask)
|
64
|
+
@logger.info("Configuring NIC #{net_connection_id} using static ip #{ip}")
|
65
|
+
#netsh interface ip set address "Local Area Connection 2" static 192.168.33.10 255.255.255.0
|
66
|
+
netsh = "netsh interface ip set address \"#{net_connection_id}\" static #{ip} #{netmask}"
|
67
|
+
@winrmshell.powershell(netsh)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Sets all networks on the guest to 'Work Network' mode. This is
|
71
|
+
# to allow guest access from the host via a private IP on Win7
|
72
|
+
# https://github.com/WinRb/vagrant-windows/issues/63
|
73
|
+
def set_all_networks_to_work()
|
74
|
+
@logger.info("Setting all networks to 'Work Network'")
|
75
|
+
command = VagrantWindows.load_script("set_work_network.ps1")
|
76
|
+
@winrmshell.powershell(command)
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
protected
|
81
|
+
|
82
|
+
# Checks the WinRS version on the guest. Usually 2 on Windows 7/2008
|
83
|
+
# and 3 on Windows 8/2012.
|
84
|
+
#
|
85
|
+
# @return [Integer]
|
86
|
+
def wsman_version()
|
87
|
+
@logger.debug("querying WSMan version")
|
88
|
+
version = ''
|
89
|
+
@winrmshell.powershell(PS_GET_WSMAN_VER) do |type, line|
|
90
|
+
version = version + "#{line}" if type == :stdout && !line.nil?
|
91
|
+
end
|
92
|
+
@logger.debug("wsman version: #{version}")
|
93
|
+
Integer(version)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Returns an array of all NICs on the guest. Each array entry is a
|
97
|
+
# Hash of the NICs properties. This method should only be used on
|
98
|
+
# guests that have WinRS version 2.
|
99
|
+
#
|
100
|
+
# @return [Array]
|
101
|
+
def network_adapters_v2_winrm()
|
102
|
+
@logger.debug("querying network adapters")
|
103
|
+
# Get all NICs that have a MAC address
|
104
|
+
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa394216(v=vs.85).aspx
|
105
|
+
adapters = @winrmshell.wql(WQL_NET_ADAPTERS_V2)[:win32_network_adapter]
|
106
|
+
@logger.debug("#{adapters.inspect}")
|
107
|
+
return adapters
|
108
|
+
end
|
109
|
+
|
110
|
+
# Returns an array of all NICs on the guest. Each array entry is a
|
111
|
+
# Hash of the NICs properties. This method should only be used on
|
112
|
+
# guests that have WinRS version 3.
|
113
|
+
#
|
114
|
+
# This method is a workaround until the WinRM gem supports WinRS version 3.
|
115
|
+
#
|
116
|
+
# @return [Array]
|
117
|
+
def network_adapters_v3_winrm()
|
118
|
+
winrs_v3_get_adapters_ps1 = VagrantWindows.load_script("winrs_v3_get_adapters.ps1")
|
119
|
+
output = ''
|
120
|
+
@winrmshell.powershell(winrs_v3_get_adapters_ps1) do |type, line|
|
121
|
+
output = output + "#{line}" if type == :stdout && !line.nil?
|
122
|
+
end
|
123
|
+
adapters = []
|
124
|
+
JSON.parse(output).each do |nic|
|
125
|
+
adapters << nic.inject({}){ |memo,(k,v)| memo[k.to_sym] = v; memo }
|
126
|
+
end
|
127
|
+
@logger.debug("#{adapters.inspect}")
|
128
|
+
return adapters
|
129
|
+
end
|
130
|
+
|
131
|
+
end #GuestNetwork class
|
132
|
+
end
|
133
|
+
end
|
@@ -1,21 +1,17 @@
|
|
1
1
|
require 'timeout'
|
2
|
-
require 'winrm'
|
3
2
|
require 'log4r'
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
require 'vagrant/util/retryable'
|
3
|
+
require_relative '../errors'
|
4
|
+
require_relative 'winrmshell'
|
5
|
+
require_relative 'winrmfinder'
|
8
6
|
|
9
7
|
module VagrantWindows
|
10
8
|
module Communication
|
11
9
|
# Provides communication with the VM via WinRM.
|
12
10
|
class WinRMCommunicator < Vagrant.plugin("2", :communicator)
|
13
11
|
|
14
|
-
include Vagrant::Util::ANSIEscapeCodeRemover
|
15
|
-
include Vagrant::Util::Retryable
|
16
|
-
|
17
12
|
attr_reader :logger
|
18
13
|
attr_reader :machine
|
14
|
+
attr_reader :winrm_finder
|
19
15
|
|
20
16
|
def self.match?(machine)
|
21
17
|
machine.config.vm.guest.eql? :windows
|
@@ -25,85 +21,44 @@ module VagrantWindows
|
|
25
21
|
@machine = machine
|
26
22
|
@logger = Log4r::Logger.new("vagrant_windows::communication::winrmcommunicator")
|
27
23
|
@logger.debug("initializing WinRMCommunicator")
|
24
|
+
@winrm_finder = WinRMFinder.new(machine)
|
28
25
|
end
|
29
26
|
|
30
27
|
def ready?
|
31
28
|
logger.debug("Checking whether WinRM is ready...")
|
32
|
-
|
29
|
+
|
33
30
|
Timeout.timeout(@machine.config.winrm.timeout) do
|
34
|
-
|
35
|
-
@logger.debug("hostname: #{data}")
|
36
|
-
end
|
31
|
+
session.powershell("hostname")
|
37
32
|
end
|
38
33
|
|
39
|
-
|
40
|
-
|
41
|
-
|
34
|
+
logger.info("WinRM is ready!")
|
35
|
+
return true
|
36
|
+
|
37
|
+
rescue Vagrant::Errors::VagrantError => e
|
38
|
+
# We catch a `VagrantError` which would signal that something went
|
39
|
+
# wrong expectedly in the `connect`, which means we didn't connect.
|
40
|
+
@logger.info("WinRM not up: #{e.inspect}")
|
41
|
+
return false
|
42
42
|
end
|
43
43
|
|
44
|
-
def execute(command, opts=
|
45
|
-
opts
|
46
|
-
:
|
47
|
-
|
48
|
-
:error_key => :winrm_bad_exit_status,
|
49
|
-
:command => command,
|
50
|
-
:sudo => false,
|
51
|
-
:shell => :powershell
|
52
|
-
}.merge(opts || {})
|
53
|
-
|
54
|
-
if opts[:shell].eql? :powershell
|
44
|
+
def execute(command, opts={}, &block)
|
45
|
+
if opts[:shell].eql? :cmd
|
46
|
+
session.cmd(command, &block)[:exitcode]
|
47
|
+
else
|
55
48
|
command = VagrantWindows.load_script("command_alias.ps1") << "\r\n" << command
|
49
|
+
session.powershell(command, &block)[:exitcode]
|
56
50
|
end
|
57
|
-
exit_status = 0
|
58
|
-
|
59
|
-
begin
|
60
|
-
# Connect via WinRM and execute the command in the shell.
|
61
|
-
exceptions = [HTTPClient::KeepAliveDisconnected]
|
62
|
-
exit_status = retryable(:tries => @machine.config.winrm.max_tries, :on => exceptions, :sleep => 10) do
|
63
|
-
shell_execute(command, opts[:shell], &block)
|
64
|
-
end
|
65
|
-
rescue StandardError => e
|
66
|
-
# return a more specific auth error for 401 errors
|
67
|
-
if e.message.include?("401")
|
68
|
-
raise Errors::WinRMAuthorizationError,
|
69
|
-
:user => @machine.config.winrm.username,
|
70
|
-
:password => @machine.config.winrm.password,
|
71
|
-
:endpoint => endpoint,
|
72
|
-
:message => e.message
|
73
|
-
end
|
74
|
-
# failed for an unknown reason, didn't even get an exit status
|
75
|
-
raise Errors::WinRMExecutionError,
|
76
|
-
:shell => opts[:shell],
|
77
|
-
:command => command,
|
78
|
-
:message => e.message
|
79
|
-
end
|
80
|
-
|
81
|
-
# Check for any exit status errors
|
82
|
-
if opts[:error_check] && exit_status != 0
|
83
|
-
error_opts = opts.merge(:_key => opts[:error_key], :exit_status => exit_status)
|
84
|
-
raise error_opts[:error_class], error_opts
|
85
|
-
end
|
86
|
-
|
87
|
-
exit_status
|
88
|
-
end
|
89
|
-
|
90
|
-
# Wrap Sudo in execute.... One day we could integrate with UAC, but Icky
|
91
|
-
def sudo(command, opts=nil, &block)
|
92
|
-
execute(command, opts, &block)
|
93
|
-
end
|
94
|
-
|
95
|
-
def download(from, to=nil)
|
96
|
-
@logger.warn("Downloading: #{from} to #{to} not supported on Windows guests")
|
97
51
|
end
|
52
|
+
alias_method :sudo, :execute
|
98
53
|
|
99
54
|
def test(command, opts=nil)
|
100
|
-
|
101
|
-
|
55
|
+
# HACK: to speed up Vagrant 1.2 OS detection, skip checking for *nix OS
|
56
|
+
return false unless (command =~ /^uname|^cat \/etc|^cat \/proc|grep 'Fedora/).nil?
|
57
|
+
execute(command) == 0
|
102
58
|
end
|
103
|
-
|
59
|
+
|
104
60
|
def upload(from, to)
|
105
61
|
@logger.debug("Uploading: #{from} to #{to}")
|
106
|
-
|
107
62
|
file = "winrm-upload-#{rand()}"
|
108
63
|
file_name = (session.cmd("echo %TEMP%\\#{file}"))[:data][0][:stdout].chomp
|
109
64
|
session.powershell <<-EOH
|
@@ -113,103 +68,53 @@ module VagrantWindows
|
|
113
68
|
}
|
114
69
|
EOH
|
115
70
|
Base64.encode64(IO.binread(from)).gsub("\n",'').chars.to_a.each_slice(8000-file_name.size) do |chunk|
|
116
|
-
out = session.cmd(
|
71
|
+
out = session.cmd("echo #{chunk.join} >> \"#{file_name}\"")
|
117
72
|
end
|
118
|
-
|
119
|
-
|
73
|
+
session.powershell("mkdir $([System.IO.Path]::GetDirectoryName(\"#{to}\"))")
|
74
|
+
session.powershell <<-EOH
|
120
75
|
$base64_string = Get-Content \"#{file_name}\"
|
121
76
|
$bytes = [System.Convert]::FromBase64String($base64_string)
|
122
77
|
$new_file = [System.IO.Path]::GetFullPath(\"#{to}\")
|
123
78
|
[System.IO.File]::WriteAllBytes($new_file,$bytes)
|
124
79
|
EOH
|
125
80
|
end
|
126
|
-
|
127
|
-
def
|
128
|
-
|
129
|
-
logger.debug("Creating WinRM session to #{endpoint} with options: #{opts}")
|
130
|
-
|
131
|
-
client = ::WinRM::WinRMWebService.new(endpoint, :plaintext, opts)
|
132
|
-
client.set_timeout(opts[:operation_timeout])
|
133
|
-
client.toggle_nori_type_casting(:off) #we don't want coersion of types
|
134
|
-
client
|
81
|
+
|
82
|
+
def download(from, to=nil)
|
83
|
+
@logger.warn("Downloading: #{from} to #{to} not supported on Windows guests")
|
135
84
|
end
|
136
|
-
|
137
|
-
|
138
|
-
|
85
|
+
|
86
|
+
# Runs a remote WQL query against the VM
|
87
|
+
#
|
88
|
+
# Note: This is not part of the standard Vagrant communicator interface, but
|
89
|
+
# guest capabilities may need to use this.
|
90
|
+
def wql(query)
|
91
|
+
session.wql(query)
|
139
92
|
end
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
def endpoint_options
|
144
|
-
{
|
145
|
-
:user => @machine.config.winrm.username,
|
146
|
-
:pass => @machine.config.winrm.password,
|
147
|
-
:host => @machine.config.winrm.host,
|
148
|
-
:port => winrm_port(),
|
149
|
-
:operation_timeout => @machine.config.winrm.timeout,
|
150
|
-
:basic_auth_only => true
|
151
|
-
}.merge ({})
|
93
|
+
|
94
|
+
def set_winrmshell(winrmshell)
|
95
|
+
@session = winrmshell
|
152
96
|
end
|
153
97
|
|
154
|
-
def
|
155
|
-
@
|
98
|
+
def session
|
99
|
+
@session ||= new_session
|
156
100
|
end
|
101
|
+
alias_method :winrmshell, :session
|
157
102
|
|
158
|
-
def find_winrm_host_port
|
159
|
-
expected_guest_port = @machine.config.winrm.guest_port
|
160
|
-
@logger.debug("Searching for WinRM port: #{expected_guest_port.inspect}")
|
161
103
|
|
162
|
-
|
163
|
-
@machine.provider.driver.read_forwarded_ports.each do |_, _, hostport, guestport|
|
164
|
-
return hostport if guestport == expected_guest_port
|
165
|
-
end
|
166
|
-
|
167
|
-
@machine.config.winrm.port
|
168
|
-
end
|
169
|
-
|
170
|
-
def endpoint
|
171
|
-
if !@winrm_endpoint
|
172
|
-
opts = endpoint_options()
|
173
|
-
@winrm_endpoint = "http://#{opts[:host]}:#{opts[:port]}/wsman"
|
174
|
-
end
|
175
|
-
@winrm_endpoint
|
176
|
-
end
|
177
|
-
|
178
|
-
# Executes the command on an SSH connection within a login shell.
|
179
|
-
def shell_execute(command, shell=:powershell, &block)
|
180
|
-
@logger.debug("#{shell} executing:\n#{command}")
|
181
|
-
|
182
|
-
if shell.eql? :cmd
|
183
|
-
output = session.cmd(command) do |out, err|
|
184
|
-
handle_out(:stdout, out, &block)
|
185
|
-
handle_out(:stderr, err, &block)
|
186
|
-
end
|
187
|
-
elsif shell.eql? :powershell
|
188
|
-
output = session.powershell(command) do |out, err|
|
189
|
-
handle_out(:stdout, out, &block)
|
190
|
-
handle_out(:stderr, err, &block)
|
191
|
-
end
|
192
|
-
else
|
193
|
-
raise Errors::WinRMInvalidShell, :shell => shell
|
194
|
-
end
|
195
|
-
|
196
|
-
exit_status = output[:exitcode]
|
197
|
-
@logger.debug("Exit status: #{exit_status.inspect}")
|
198
|
-
|
199
|
-
# Return the final exit status
|
200
|
-
return exit_status
|
201
|
-
end
|
104
|
+
protected
|
202
105
|
|
203
|
-
def
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
106
|
+
def new_session
|
107
|
+
WinRMShell.new(
|
108
|
+
@winrm_finder.winrm_host_address(),
|
109
|
+
@machine.config.winrm.username,
|
110
|
+
@machine.config.winrm.password,
|
111
|
+
{
|
112
|
+
:port => @winrm_finder.winrm_host_port(),
|
113
|
+
:timeout_in_seconds => @machine.config.winrm.timeout,
|
114
|
+
:max_tries => @machine.config.winrm.max_tries
|
115
|
+
})
|
211
116
|
end
|
212
|
-
|
117
|
+
|
213
118
|
end #WinRM class
|
214
119
|
end
|
215
120
|
end
|