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.
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