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
@@ -1,5 +1,6 @@
1
1
  module VagrantWindows
2
2
  module Helper
3
+ extend self
3
4
 
4
5
  def win_friendly_path(path)
5
6
  if path
@@ -8,6 +9,11 @@ module VagrantWindows
8
9
  end
9
10
  new_path
10
11
  end
12
+
13
+ # turns '/vagrant' into 'vagrant' or turns ''/a/b/c/d/e' into 'a_b_c_d_e'
14
+ def win_friendly_share_id(shared_folder_name)
15
+ return shared_folder_name.gsub(/[\/\/]/,'_').sub(/^_/, '')
16
+ end
11
17
 
12
18
  end
13
19
  end
@@ -1,3 +1,6 @@
1
+ require_relative '../../../helper'
2
+ require_relative '../../../communication/winrmcommunicator'
3
+
1
4
  module Vagrant
2
5
  class Machine
3
6
 
@@ -21,5 +24,9 @@ module Vagrant
21
24
  @winrm ||= WinRM.new(self)
22
25
  end
23
26
 
27
+ def is_windows?
28
+ return @config.vm.guest.eql? :windows
29
+ end
30
+
24
31
  end
25
32
  end
@@ -0,0 +1,44 @@
1
+ require "#{Vagrant::source_root}/plugins/providers/virtualbox/action/share_folders"
2
+ require_relative '../../../../../helper'
3
+
4
+ module VagrantPlugins
5
+ module ProviderVirtualBox
6
+ module Action
7
+ class ShareFolders
8
+ include VagrantWindows::Helper
9
+
10
+ alias_method :original_create_metadata, :create_metadata
11
+
12
+ def create_metadata
13
+
14
+ unless @env[:machine].is_windows?
15
+ # don't change the shared folder name for linux guests. We don't want the shared folder name of linux guests to be different
16
+ # depending on whether the vagrant-windows plugin is installed or not.
17
+ original_create_metadata
18
+ else
19
+ @env[:ui].info I18n.t("vagrant.actions.vm.share_folders.creating")
20
+
21
+ folders = []
22
+ shared_folders.each do |id, data|
23
+ hostpath = File.expand_path(data[:hostpath], @env[:root_path])
24
+ hostpath = Vagrant::Util::Platform.cygwin_windows_path(hostpath)
25
+
26
+ folder_name = win_friendly_share_id(id.gsub(/[\/\/]/,'_').sub(/^_/, ''))
27
+
28
+ folders << {
29
+ :name => folder_name,
30
+ :hostpath => hostpath,
31
+ :transient => data[:transient]
32
+ }
33
+ end
34
+
35
+ @env[:machine].provider.driver.share_folders(folders)
36
+ end
37
+ end
38
+
39
+
40
+
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,106 @@
1
+ require 'tempfile'
2
+ require "#{Vagrant::source_root}/plugins/provisioners/chef/provisioner/chef_solo"
3
+ require_relative '../../../../../helper'
4
+
5
+ module VagrantPlugins
6
+ module Chef
7
+ module Provisioner
8
+ class ChefSolo < Base
9
+
10
+ include VagrantWindows::Helper
11
+
12
+ run_chef_solo_on_linux = instance_method(:run_chef_solo)
13
+
14
+ # This patch is needed until Vagrant supports chef on Windows guests
15
+ define_method(:run_chef_solo) do
16
+ is_windows ? run_chef_solo_on_windows() : run_chef_solo_on_linux.bind(self).()
17
+ end
18
+
19
+ def run_chef_solo_on_windows
20
+ # create cheftaskrun.ps1 that the scheduled task will invoke when run
21
+ render_file_and_upload("cheftaskrun.ps1", chef_script_options[:chef_task_run_ps1], :options => chef_script_options)
22
+
23
+ # create cheftask.xml that the scheduled task will be created with
24
+ render_file_and_upload("cheftask.xml", chef_script_options[:chef_task_xml], :options => chef_script_options)
25
+
26
+ # create cheftask.ps1 that will immediately invoke the scheduled task and wait for completion
27
+ render_file_and_upload("cheftask.ps1", chef_script_options[:chef_task_ps1], :options => chef_script_options)
28
+
29
+ command = <<-EOH
30
+ $old = Get-ExecutionPolicy;
31
+ Set-ExecutionPolicy Unrestricted -force;
32
+ #{chef_script_options[:chef_task_ps1]};
33
+ Set-ExecutionPolicy $old -force
34
+ exit $LASTEXITCODE
35
+ EOH
36
+
37
+ @config.attempts.times do |attempt|
38
+ if attempt == 0
39
+ @machine.env.ui.info I18n.t("vagrant.provisioners.chef.running_solo")
40
+ else
41
+ @machine.env.ui.info I18n.t("vagrant.provisioners.chef.running_solo_again")
42
+ end
43
+
44
+ exit_status = @machine.communicate.execute(command) do |type, data|
45
+ # Output the data with the proper color based on the stream.
46
+ color = type == :stdout ? :green : :red
47
+
48
+ @machine.env.ui.info(
49
+ data, :color => color, :new_line => false, :prefix => false)
50
+ end
51
+
52
+ # There is no need to run Chef again if it converges
53
+ return if exit_status == 0
54
+ end
55
+
56
+ # If we reached this point then Chef never converged! Error.
57
+ raise ChefError, :no_convergence
58
+ end
59
+
60
+ def render_file_and_upload(script_name, dest_file, options)
61
+ script_contents = VagrantWindows.load_script_template(script_name, options)
62
+
63
+ # render cheftaskrun.ps1 to local temp file
64
+ script_local = Tempfile.new(script_name)
65
+ IO.write(script_local, script_contents)
66
+
67
+ # upload cheftaskrun.ps1 file
68
+ @machine.communicate.upload(script_local, dest_file)
69
+ end
70
+
71
+ def chef_script_options
72
+ if @chef_script_options.nil?
73
+ command_env = @config.binary_env ? "#{@config.binary_env} " : ""
74
+ command_args = @config.arguments ? " #{@config.arguments}" : ""
75
+ chef_solo_path = win_friendly_path(File.join(@config.provisioning_path, 'solo.rb'))
76
+ chef_dna_path = win_friendly_path(File.join(@config.provisioning_path, 'dna.json'))
77
+
78
+ chef_arguments = "-c #{chef_solo_path} "
79
+ chef_arguments << "-j #{chef_dna_path} "
80
+ chef_arguments << "#{command_args}"
81
+
82
+ @chef_script_options = {
83
+ :user => @machine.config.winrm.username,
84
+ :pass => @machine.config.winrm.password,
85
+ :chef_arguments => chef_arguments,
86
+ :chef_task_xml => win_friendly_path("#{@config.provisioning_path}/cheftask.xml"),
87
+ :chef_task_running => win_friendly_path("#{@config.provisioning_path}/cheftask.running"),
88
+ :chef_task_exitcode => win_friendly_path("#{@config.provisioning_path}/cheftask.exitcode"),
89
+ :chef_task_ps1 => win_friendly_path("#{@config.provisioning_path}/cheftask.ps1"),
90
+ :chef_task_run_ps1 => win_friendly_path("#{@config.provisioning_path}/cheftaskrun.ps1"),
91
+ :chef_stdout_log => win_friendly_path("#{@config.provisioning_path}/chef-solo.log"),
92
+ :chef_stderr_log => win_friendly_path("#{@config.provisioning_path}/chef-solo.err.log"),
93
+ :chef_binary_path => win_friendly_path("#{command_env}#{chef_binary_path("chef-solo")}")
94
+ }
95
+ end
96
+ @chef_script_options
97
+ end
98
+
99
+ def is_windows
100
+ @machine.config.vm.guest.eql? :windows
101
+ end
102
+
103
+ end # ChefSolo class
104
+ end
105
+ end
106
+ end
@@ -22,7 +22,7 @@ module VagrantPlugins
22
22
  module_paths = @module_paths.map { |_, to| to }
23
23
  if !@module_paths.empty?
24
24
  # Prepend the default module path
25
- module_paths.unshift("/etc/puppet/modules")
25
+ module_paths.unshift("/ProgramData/PuppetLabs/puppet/etc/modules")
26
26
 
27
27
  # Add the command line switch to add the module path
28
28
  options << "--modulepath '#{module_paths.join(';')}'"
@@ -48,8 +48,9 @@ module VagrantPlugins
48
48
  :manifest => @manifest_file)
49
49
 
50
50
  @machine.communicate.sudo(command) do |type, data|
51
- data.chomp!
52
- @machine.env.ui.info(data, :prefix => false) if !data.empty?
51
+ if !data.empty?
52
+ @machine.env.ui.info(data, :new_line => false, :prefix => false)
53
+ end
53
54
  end
54
55
  end
55
56
 
@@ -63,7 +64,7 @@ module VagrantPlugins
63
64
  # Setup the module paths
64
65
  @module_paths = []
65
66
  @expanded_module_paths.each_with_index do |path, i|
66
- @module_paths << [path, File.join(config.pp_path, "modules-#{i}")]
67
+ @module_paths << [path, File.join(config.temp_dir, "modules-#{i}")]
67
68
  end
68
69
 
69
70
  @logger.debug("Syncing folders from puppet configure")
@@ -1,5 +1,5 @@
1
1
  require "#{Vagrant::source_root}/plugins/provisioners/shell/provisioner"
2
- require "vagrant-windows/helper"
2
+ require_relative '../../../../helper'
3
3
 
4
4
  module VagrantPlugins
5
5
  module Shell
@@ -43,9 +43,9 @@ module VagrantPlugins
43
43
  # Output the data with the proper color based on the stream.
44
44
  color = type == :stdout ? :green : :red
45
45
 
46
- # Note: Be sure to chomp the data to avoid the newlines that the
47
- # Chef outputs.
48
- @machine.env.ui.info(data.chomp, :color => color, :prefix => false)
46
+ @machine.ui.info(
47
+ data,
48
+ :color => color, :new_line => false, :prefix => false)
49
49
  end
50
50
  end
51
51
 
@@ -10,35 +10,28 @@ if Vagrant::VERSION < "1.1.0"
10
10
  raise "The Vagrant Windows plugin is only compatible with Vagrant 1.1+"
11
11
  end
12
12
 
13
- # Add vagrant-windows plugin errors
14
- require "vagrant-windows/errors"
15
-
16
- # Add Vagrant WinRM communication channel
17
- require "vagrant-windows/communication/winrmcommunicator"
13
+ if Vagrant::VERSION >= "1.2.0"
14
+ # Monkey Patch the virtualbox share_folders action to make valid share names on windows
15
+ require_relative "monkey_patches/plugins/providers/virtualbox/action/share_folders"
16
+ end
18
17
 
19
- # Monkey patch the vbox42 driver
20
- require "vagrant-windows/monkey_patches/vbox_42_driver"
18
+ # Monkey patch the vbox42 driver to support read mac addresses
19
+ require_relative "monkey_patches/plugins/providers/virtualbox/driver/version_4_2"
21
20
 
22
21
  # Monkey Patch the VM object to support multiple channels, i.e. WinRM
23
- require "vagrant-windows/monkey_patches/machine"
22
+ require_relative "monkey_patches/lib/vagrant/machine"
24
23
 
25
- # Monkey patch the Puppet provisioner to support PowerShell/Windows
26
- require "vagrant-windows/monkey_patches/puppet"
24
+ # Monkey patch the Puppet provisioners to support PowerShell/Windows
25
+ require_relative "monkey_patches/plugins/provisioners/puppet/provisioner/puppet"
26
+ require_relative "monkey_patches/plugins/provisioners/puppet/provisioner/puppet_server"
27
27
 
28
- # Monkey patch the Chef-Solo provisioner to support PowerShell/Windows
29
- require "vagrant-windows/monkey_patches/chef_solo"
28
+ # Monkey patch the Chef provisioners to support PowerShell/Windows
29
+ require_relative "monkey_patches/plugins/provisioners/chef/provisioner/chef_solo"
30
+ require_relative "monkey_patches/plugins/provisioners/chef/provisioner/chef_client"
30
31
 
31
32
  # Monkey patch the shell provisioner to support PowerShell/batch/exe/Windows/etc
32
- require "vagrant-windows/monkey_patches/provisioner"
33
-
34
- # Add our windows specific config object
35
- require "vagrant-windows/config/windows"
36
-
37
- # Add our winrm specific config object
38
- require "vagrant-windows/config/winrm"
33
+ require_relative "monkey_patches/plugins/provisioners/shell/provisioner"
39
34
 
40
- # Add the new Vagrant Windows guest
41
- require "vagrant-windows/guest/windows"
42
35
 
43
36
  module VagrantWindows
44
37
  class Plugin < Vagrant.plugin("2")
@@ -47,19 +40,53 @@ module VagrantWindows
47
40
  This plugin installs a provider that allows Vagrant to manage
48
41
  Windows machines as guests.
49
42
  DESC
50
-
51
- guest(:windows) do
52
- VagrantWindows::Guest::Windows
53
- end
54
-
43
+
55
44
  config(:windows) do
45
+ require_relative "config/windows"
56
46
  VagrantWindows::Config::Windows
57
47
  end
58
-
48
+
59
49
  config(:winrm) do
50
+ require_relative "config/winrm"
60
51
  VagrantWindows::Config::WinRM
61
52
  end
53
+
54
+ guest(:windows) do
55
+ require_relative "guest/windows"
56
+ VagrantWindows::Guest::Windows
57
+ end
58
+
59
+ # Vagrant 1.2 introduced the concept of capabilities instead of implementing
60
+ # an interface on the guest.
61
+ if Vagrant::VERSION >= "1.2.0"
62
+
63
+ guest_capability(:windows, :change_host_name) do
64
+ require_relative "guest/cap/change_host_name"
65
+ VagrantWindows::Guest::Cap::ChangeHostName
66
+ end
67
+
68
+ guest_capability(:windows, :configure_networks) do
69
+ require_relative "guest/cap/configure_networks"
70
+ VagrantWindows::Guest::Cap::ConfigureNetworks
71
+ end
72
+
73
+ guest_capability(:windows, :halt) do
74
+ require_relative "guest/cap/halt"
75
+ VagrantWindows::Guest::Cap::Halt
76
+ end
77
+
78
+ guest_capability(:windows, :mount_virtualbox_shared_folder) do
79
+ require_relative "guest/cap/mount_virtualbox_shared_folder"
80
+ VagrantWindows::Guest::Cap::MountVirtualBoxSharedFolder
81
+ end
82
+
83
+ guest_capability(:windows, :mount_vmware_shared_folder) do
84
+ require_relative "guest/cap/mount_vmware_shared_folder"
85
+ VagrantWindows::Guest::Cap::MountVMwareSharedFolder
86
+ end
62
87
 
88
+ end
89
+
63
90
  # This initializes the internationalization strings.
64
91
  def self.setup_i18n
65
92
  I18n.load_path << File.expand_path("locales/en.yml", VagrantWindows.vagrant_windows_root)
@@ -0,0 +1,47 @@
1
+ schtasks /query /tn "chef-solo" | Out-Null
2
+ if ($?) {
3
+ # task already exists, kill it
4
+ schtasks /delete /tn "chef-solo" /f | Out-Null
5
+ }
6
+
7
+ # Ensure the chef task running file doesn't exist from a previous failure
8
+ if (Test-Path "<%= options[:chef_task_running] %>") {
9
+ del "<%= options[:chef_task_running] %>"
10
+ }
11
+
12
+ # schedule the task to run once in the far distant future
13
+ schtasks /create /tn "chef-solo" /xml "<%= options[:chef_task_xml] %>" /ru "<%= options[:user] %>" /rp "<%= options[:pass] %>" | Out-Null
14
+
15
+ # start the scheduled task right now
16
+ schtasks /run /tn "chef-solo" | Out-Null
17
+
18
+ # wait for run_chef.ps1 to start or timeout after 1 minute
19
+ $timeoutSeconds = 60
20
+ $elapsedSeconds = 0
21
+ while ( (!(Test-Path "<%= options[:chef_task_running] %>")) -and ($elapsedSeconds -lt $timeoutSeconds) ) {
22
+ Start-Sleep -s 1
23
+ $elapsedSeconds++
24
+ }
25
+
26
+ if ($elapsedSeconds -ge $timeoutSeconds) {
27
+ Write-Error "Timed out waiting for chef scheduled task to start"
28
+ exit -2
29
+ }
30
+
31
+ # read the entire file, but only write out new lines we haven't seen before
32
+ $numLinesRead = 0
33
+ $success = $TRUE
34
+ while (Test-Path "<%= options[:chef_task_running] %>") {
35
+ Start-Sleep -m 100
36
+
37
+ $text = (get-content "<%= options[:chef_stdout_log] %>")
38
+ $numLines = ($text | Measure-Object -line).lines
39
+ $numLinesToRead = $numLines - $numLinesRead
40
+
41
+ $text | select -first $numLinesToRead -skip $numLinesRead | ForEach {
42
+ Write-Host "$_"
43
+ }
44
+ $numLinesRead += $numLinesToRead
45
+ }
46
+
47
+ exit Get-Content "<%= options[:chef_task_exitcode] %>"
@@ -0,0 +1,45 @@
1
+ <?xml version="1.0" encoding="UTF-16"?>
2
+ <Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
3
+ <RegistrationInfo>
4
+ <Date>2013-06-21T22:41:43</Date>
5
+ <Author>Administrator</Author>
6
+ </RegistrationInfo>
7
+ <Triggers>
8
+ <TimeTrigger>
9
+ <StartBoundary>2045-01-01T12:00:00</StartBoundary>
10
+ <Enabled>true</Enabled>
11
+ </TimeTrigger>
12
+ </Triggers>
13
+ <Principals>
14
+ <Principal id="Author">
15
+ <UserId>vagrant</UserId>
16
+ <LogonType>Password</LogonType>
17
+ <RunLevel>HighestAvailable</RunLevel>
18
+ </Principal>
19
+ </Principals>
20
+ <Settings>
21
+ <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
22
+ <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
23
+ <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
24
+ <AllowHardTerminate>true</AllowHardTerminate>
25
+ <StartWhenAvailable>false</StartWhenAvailable>
26
+ <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
27
+ <IdleSettings>
28
+ <StopOnIdleEnd>true</StopOnIdleEnd>
29
+ <RestartOnIdle>false</RestartOnIdle>
30
+ </IdleSettings>
31
+ <AllowStartOnDemand>true</AllowStartOnDemand>
32
+ <Enabled>true</Enabled>
33
+ <Hidden>false</Hidden>
34
+ <RunOnlyIfIdle>false</RunOnlyIfIdle>
35
+ <WakeToRun>false</WakeToRun>
36
+ <ExecutionTimeLimit>PT2H</ExecutionTimeLimit>
37
+ <Priority>7</Priority>
38
+ </Settings>
39
+ <Actions Context="Author">
40
+ <Exec>
41
+ <Command>powershell</Command>
42
+ <Arguments>-file <%= options[:chef_task_run_ps1] %></Arguments>
43
+ </Exec>
44
+ </Actions>
45
+ </Task>