vagrant-windows 1.0.3 → 1.2.0
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.
- 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
|