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.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.travis.yml +5 -0
  4. data/Gemfile +1 -1
  5. data/README.md +77 -20
  6. data/Rakefile +14 -4
  7. data/lib/vagrant-windows/communication/guestnetwork.rb +133 -0
  8. data/lib/vagrant-windows/communication/winrmcommunicator.rb +56 -151
  9. data/lib/vagrant-windows/communication/winrmfinder.rb +45 -0
  10. data/lib/vagrant-windows/communication/winrmshell.rb +141 -0
  11. data/lib/vagrant-windows/config/windows.rb +4 -0
  12. data/lib/vagrant-windows/config/winrm.rb +1 -1
  13. data/lib/vagrant-windows/guest/cap/change_host_name.rb +14 -0
  14. data/lib/vagrant-windows/guest/cap/configure_networks.rb +69 -0
  15. data/lib/vagrant-windows/guest/cap/halt.rb +22 -0
  16. data/lib/vagrant-windows/guest/cap/mount_virtualbox_shared_folder.rb +17 -0
  17. data/lib/vagrant-windows/guest/cap/mount_vmware_shared_folder.rb +15 -0
  18. data/lib/vagrant-windows/guest/windows.rb +46 -77
  19. data/lib/vagrant-windows/helper.rb +6 -0
  20. data/lib/vagrant-windows/monkey_patches/{machine.rb → lib/vagrant/machine.rb} +7 -0
  21. data/lib/vagrant-windows/monkey_patches/plugins/providers/virtualbox/action/share_folders.rb +44 -0
  22. data/lib/vagrant-windows/monkey_patches/{vbox_42_driver.rb → plugins/providers/virtualbox/driver/version_4_2.rb} +0 -0
  23. data/lib/vagrant-windows/monkey_patches/plugins/provisioners/chef/provisioner/chef_client.rb +1 -0
  24. data/lib/vagrant-windows/monkey_patches/plugins/provisioners/chef/provisioner/chef_solo.rb +106 -0
  25. data/lib/vagrant-windows/monkey_patches/{puppet.rb → plugins/provisioners/puppet/provisioner/puppet.rb} +5 -4
  26. data/lib/vagrant-windows/monkey_patches/plugins/provisioners/puppet/provisioner/puppet_server.rb +1 -0
  27. data/lib/vagrant-windows/monkey_patches/{provisioner.rb → plugins/provisioners/shell/provisioner.rb} +4 -4
  28. data/lib/vagrant-windows/plugin.rb +54 -27
  29. data/lib/vagrant-windows/scripts/cheftask.ps1.erb +47 -0
  30. data/lib/vagrant-windows/scripts/cheftask.xml.erb +45 -0
  31. data/lib/vagrant-windows/scripts/cheftaskrun.ps1.erb +16 -0
  32. data/lib/vagrant-windows/scripts/command_alias.ps1 +4 -0
  33. data/lib/vagrant-windows/scripts/{mount_volume.ps1.erb → mount_volume.virtualbox.ps1.erb} +1 -1
  34. data/lib/vagrant-windows/scripts/mount_volume.vmware.ps1.erb +49 -0
  35. data/lib/vagrant-windows/scripts/set_work_network.ps1 +6 -0
  36. data/lib/vagrant-windows/scripts/winrs_v3_get_adapters.ps1 +11 -0
  37. data/lib/vagrant-windows/version.rb +1 -1
  38. data/spec/spec_helper.rb +14 -0
  39. data/spec/vagrant-windows/config_spec.rb +3 -4
  40. data/spec/vagrant-windows/guestnetwork_spec.rb +47 -0
  41. data/spec/vagrant-windows/helper_spec.rb +14 -3
  42. data/spec/vagrant-windows/winrmcommunicator_spec.rb +26 -0
  43. data/vagrant-windows.gemspec +33 -2
  44. metadata +100 -55
  45. data/lib/vagrant-windows/monkey_patches/chef_solo.rb +0 -61
  46. 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
@@ -17,3 +17,4 @@ test/version_tmp
17
17
  tmp
18
18
  .vagrant
19
19
  Vagrantfile
20
+ Gemfile.lock
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 1.9.2
5
+ - 2.0.0
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.1.5'
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
- - Vagrant 1.0 should use <code>gem "vagrant-windows", "~> 0.1.2"</code>
5
- - Vagrant 1.1 should use <code>gem "vagrant-windows", "~> 1.0.0"</code>
6
- - Vagrant 1.2 is not yet supported. There needs to be a refactor to support capabilities. We are looking for a backwards compatiable way to implement this.
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
- -Enable WinRM
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
- - Create a vagrant user, for things to work out of the box username and password should both be "vagrant".
32
- - Turn off UAC (Msconfig)
33
- - Disable complex passwords
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 = 15
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 = 15
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 12.
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. Vagrant 1.2 support. Unfortunately it appears there are some breaking changes with guests between Vagrant 1.1. and 1.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
- Running tests
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
- # Install the `spec` task so that we can run tests.
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
- # Default task is to run the unit tests
15
- task :default => "build"
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
- require 'vagrant/util/ansi_escape_code_remover'
5
- require 'vagrant/util/file_mode'
6
- require 'vagrant/util/platform'
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
- execute("hostname") do |type, data|
35
- @logger.debug("hostname: #{data}")
36
- end
31
+ session.powershell("hostname")
37
32
  end
38
33
 
39
- # If we reached this point then we successfully connected
40
- logger.debug("WinRM is ready!")
41
- true
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=nil, &block)
45
- opts = {
46
- :error_check => true,
47
- :error_class => Errors::WinRMExecutionError,
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
- opts = { :error_check => false }.merge(opts || {})
101
- execute(command, opts) == 0
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( "echo #{chunk.join} >> \"#{file_name}\"" )
71
+ out = session.cmd("echo #{chunk.join} >> \"#{file_name}\"")
117
72
  end
118
- execute "mkdir $([System.IO.Path]::GetDirectoryName(\"#{to}\"))"
119
- execute <<-EOH
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 new_session
128
- opts = endpoint_options()
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
- def session
138
- @session ||= new_session
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
- protected
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 winrm_port
155
- @winrm_port ||= find_winrm_host_port()
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
- # Look for the forwarded port only by comparing the guest port
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 handle_out(type, data, &block)
204
- if block_given? && data
205
- if data =~ /\n/
206
- data.split(/\n/).each { |d| block.call(type, d) }
207
- else
208
- block.call(type, data)
209
- end
210
- end
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