vagrant-windows-hyperv 1.0.1

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 +19 -0
  3. data/Gemfile +15 -0
  4. data/LICENSE.txt +7 -0
  5. data/README.md +89 -0
  6. data/Rakefile +29 -0
  7. data/example_box/metadata.json +1 -0
  8. data/lib/vagrant-windows-hyperv.rb +38 -0
  9. data/lib/vagrant-windows-hyperv/action.rb +81 -0
  10. data/lib/vagrant-windows-hyperv/action/export.rb +54 -0
  11. data/lib/vagrant-windows-hyperv/action/package.rb +21 -0
  12. data/lib/vagrant-windows-hyperv/action/rdp.rb +49 -0
  13. data/lib/vagrant-windows-hyperv/action/setup_package_files.rb +55 -0
  14. data/lib/vagrant-windows-hyperv/command/rdp/command.rb +22 -0
  15. data/lib/vagrant-windows-hyperv/communication/powershell.rb +37 -0
  16. data/lib/vagrant-windows-hyperv/driver.rb +89 -0
  17. data/lib/vagrant-windows-hyperv/errors.rb +31 -0
  18. data/lib/vagrant-windows-hyperv/guest/cap/halt.rb +19 -0
  19. data/lib/vagrant-windows-hyperv/guest/windows.rb +25 -0
  20. data/lib/vagrant-windows-hyperv/monkey_patch/action/provision.rb +32 -0
  21. data/lib/vagrant-windows-hyperv/monkey_patch/machine.rb +22 -0
  22. data/lib/vagrant-windows-hyperv/monkey_patch/plugins/synced_folders/smb/synced_folders.rb +55 -0
  23. data/lib/vagrant-windows-hyperv/monkey_patch/util/powershell.rb +37 -0
  24. data/lib/vagrant-windows-hyperv/plugin.rb +85 -0
  25. data/lib/vagrant-windows-hyperv/provider.rb +30 -0
  26. data/lib/vagrant-windows-hyperv/provisioner/chef_solo.rb +181 -0
  27. data/lib/vagrant-windows-hyperv/provisioner/puppet.rb +99 -0
  28. data/lib/vagrant-windows-hyperv/provisioner/shell.rb +81 -0
  29. data/lib/vagrant-windows-hyperv/scripts/check_winrm.ps1 +41 -0
  30. data/lib/vagrant-windows-hyperv/scripts/export_vm.ps1 +31 -0
  31. data/lib/vagrant-windows-hyperv/scripts/file_sync.ps1 +145 -0
  32. data/lib/vagrant-windows-hyperv/scripts/host_info.ps1 +25 -0
  33. data/lib/vagrant-windows-hyperv/scripts/hyperv_manager.ps1 +36 -0
  34. data/lib/vagrant-windows-hyperv/scripts/run_in_remote.ps1 +31 -0
  35. data/lib/vagrant-windows-hyperv/scripts/upload_file.ps1 +95 -0
  36. data/lib/vagrant-windows-hyperv/scripts/utils/create_session.ps1 +34 -0
  37. data/lib/vagrant-windows-hyperv/scripts/utils/write_messages.ps1 +18 -0
  38. data/lib/vagrant-windows-hyperv/version.rb +10 -0
  39. data/locales/en.yml +15 -0
  40. data/spec/hyper-v/config_spec.rb +36 -0
  41. data/spec/hyper-v/spec_helper.rb +9 -0
  42. data/templates/provisioners/chef-solo/solo.erb +51 -0
  43. data/vagrant-windows-hyperv.gemspec +63 -0
  44. data/vagrantfile_examples/Vagrantfile_linux +23 -0
  45. data/vagrantfile_examples/Vagrantfile_windows +24 -0
  46. metadata +171 -0
@@ -0,0 +1,22 @@
1
+ #-------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Open Technologies, Inc.
3
+ # All Rights Reserved. Licensed under the Apache 2.0 License.
4
+ #--------------------------------------------------------------------------
5
+
6
+ module VagrantPlugins
7
+ module VagrantHyperV
8
+ class Command < Vagrant.plugin("2", :command)
9
+ def self.synopsis
10
+ "opens a RDP session for a vagrant machine"
11
+ end
12
+
13
+ def execute
14
+ with_target_vms do |vm|
15
+ vm.action(:rdp)
16
+ end
17
+ # Success, exit status 0
18
+ 0
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,37 @@
1
+ #-------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Open Technologies, Inc.
3
+ # All Rights Reserved. Licensed under the Apache 2.0 License.
4
+ #--------------------------------------------------------------------------
5
+
6
+ module VagrantPlugins
7
+ module VagrantHyperV
8
+ module Communicator
9
+ class PowerShell < Vagrant.plugin("2", :communicator)
10
+ def initialize(machine)
11
+ @machine = machine
12
+ end
13
+
14
+ def wait_for_ready(timeout)
15
+ ready?
16
+ end
17
+
18
+ def ready?
19
+ # Return True when the guest has enabled WinRM
20
+ # In this case we can try any remote PowerShell commands to see if
21
+ # further vagrant can be carried out using this communication
22
+ if !@winrm_status
23
+ status = false
24
+ response = @machine.provider.driver.check_winrm
25
+ @winrm_status = response["message"] == "Running"
26
+ raise Errors::WinRMNotReady if !@winrm_status
27
+ end
28
+ @winrm_status
29
+ end
30
+
31
+ def test(command, opts=nil)
32
+ true
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,89 @@
1
+ #-------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Open Technologies, Inc.
3
+ # All Rights Reserved. Licensed under the Apache 2.0 License.
4
+ #--------------------------------------------------------------------------
5
+
6
+ require "json"
7
+ require "#{Vagrant::source_root}/plugins/providers/hyperv/driver"
8
+
9
+ module VagrantPlugins
10
+ module VagrantHyperV
11
+ class Driver < VagrantPlugins::HyperV::Driver
12
+
13
+ def initialize(machine)
14
+ @vm_id = machine.id
15
+ @machine = machine
16
+ end
17
+
18
+ def ssh_info
19
+ @ssh_info ||= @machine.ssh_info
20
+ end
21
+
22
+ def remote_credentials
23
+ @remote_credentials ||= { guest_ip: ssh_info[:host],
24
+ username: ssh_info[:username],
25
+ password: "vagrant" }
26
+ end
27
+
28
+ def run_remote_ps(command, &block)
29
+ options = remote_credentials.merge(command: command)
30
+ script_path = local_script_path('run_in_remote.ps1')
31
+ # FIXME: Vagrant's core driver method which executes PowerShell,
32
+ # need to take an &block so that this piece of code can be avoided.
33
+ ps_options = []
34
+ options.each do |key, value|
35
+ ps_options << "-#{key}"
36
+ ps_options << "'#{value}'"
37
+ end
38
+ ps_options << "-ErrorAction" << "Stop"
39
+ opts = { notify: [:stdout, :stderr, :stdin] }
40
+ Vagrant::Util::PowerShell.execute(script_path, *ps_options, **opts, &block)
41
+ end
42
+
43
+ def export_vm_to(path)
44
+ options = {
45
+ vm_id: vm_id,
46
+ path: windows_path(path)
47
+ }
48
+ script_path = local_script_path('export_vm.ps1')
49
+ execute(script_path, options)
50
+ end
51
+
52
+ def upload(from, to)
53
+ options = {
54
+ vm_id: vm_id,
55
+ host_path: windows_path(from),
56
+ guest_path: windows_path(to)
57
+ }.merge(remote_credentials)
58
+ script_path = local_script_path('upload_file.ps1')
59
+ execute(script_path, options)
60
+ end
61
+
62
+ def check_winrm
63
+ script_path = local_script_path('check_winrm.ps1')
64
+ execute(script_path, remote_credentials)
65
+ end
66
+
67
+ def get_host_ip
68
+ script_path = local_script_path('host_info.ps1')
69
+ execute(script_path, {})
70
+ end
71
+
72
+ protected
73
+
74
+ def local_script_path(path)
75
+ lib_path = Pathname.new(File.expand_path("../scripts", __FILE__))
76
+ lib_path.join(path).to_s
77
+ end
78
+
79
+ def windows_path(path)
80
+ if path
81
+ path = path.gsub("/","\\")
82
+ path = "c:#{path}" if path =~ /^\\/
83
+ end
84
+ path
85
+ end
86
+
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,31 @@
1
+ #-------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Open Technologies, Inc.
3
+ # All Rights Reserved. Licensed under the Apache 2.0 License.
4
+ #--------------------------------------------------------------------------
5
+
6
+ module VagrantPlugins
7
+ module VagrantHyperV
8
+ module Errors
9
+ class VagrantHyperVError < Vagrant::Errors::VagrantError
10
+ error_namespace("vagrant_win_hyperv.errors")
11
+ end
12
+
13
+ class SSHNotAvailable < VagrantHyperVError
14
+ error_key(:ssh_not_available)
15
+ end
16
+
17
+ class RDPNotAvailable < VagrantHyperVError
18
+ error_key(:rdp_not_available)
19
+ end
20
+
21
+ class InvalidSMBCredentials < VagrantHyperVError
22
+ error_key(:no_smb_credentials)
23
+ end
24
+
25
+ class WinRMNotReady < VagrantHyperVError
26
+ error_key(:win_rm_not_available)
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,19 @@
1
+ #-------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Open Technologies, Inc.
3
+ # All Rights Reserved. Licensed under the Apache 2.0 License.
4
+ #--------------------------------------------------------------------------
5
+
6
+ module VagrantPlugins
7
+ module VagrantHyperV
8
+ module Guest
9
+ module Cap
10
+ class Halt
11
+ def self.halt(machine)
12
+ machine.provider.driver.run_remote_ps("shutdown -a")
13
+ machine.provider.driver.run_remote_ps("shutdown /s /t 1")
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,25 @@
1
+ #-------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Open Technologies, Inc.
3
+ # All Rights Reserved. Licensed under the Apache 2.0 License.
4
+ #--------------------------------------------------------------------------
5
+ require "vagrant"
6
+
7
+ module VagrantPlugins
8
+ module VagrantHyperV
9
+ module Guest
10
+ class Windows < Vagrant.plugin("2", :guest)
11
+ attr_reader :machin
12
+
13
+ def initialize(machine = nil)
14
+ super(machine) unless machine == nil
15
+ @machine = machine
16
+ end
17
+
18
+ def halt
19
+ VagrantHyperV::VagrantPlugins::Guest::Cap::Halt.halt(@machine)
20
+ end
21
+
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,32 @@
1
+ #-------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Open Technologies, Inc.
3
+ # All Rights Reserved. Licensed under the Apache 2.0 License.
4
+ #--------------------------------------------------------------------------
5
+
6
+ require "#{Vagrant::source_root}/lib/vagrant/action/builtin/provision"
7
+
8
+ module Vagrant
9
+ module Action
10
+ module Builtin
11
+ class Provision
12
+
13
+ alias_method :original_run_provisioner, :run_provisioner
14
+ # Override this method from core vagrant, here we branch out the provision for windows
15
+ def run_provisioner(env)
16
+ if env[:machine].config.vm.guest == :windows
17
+ case env[:provisioner].class.to_s
18
+ when "VagrantPlugins::Shell::Provisioner"
19
+ VagrantPlugins::VagrantHyperV::Provisioner::Shell.new(env).provision_for_windows
20
+ when "VagrantPlugins::Puppet::Provisioner::Puppet"
21
+ VagrantPlugins::VagrantHyperV::Provisioner::Puppet.new(env).provision_for_windows
22
+ when "VagrantPlugins::Chef::Provisioner::ChefSolo"
23
+ VagrantPlugins::VagrantHyperV::Provisioner::ChefSolo.new(env).provision_for_windows
24
+ end
25
+ else
26
+ original_run_provisioner(env)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,22 @@
1
+ #-------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Open Technologies, Inc.
3
+ # All Rights Reserved. Licensed under the Apache 2.0 License.
4
+ #--------------------------------------------------------------------------
5
+
6
+ module Vagrant
7
+ class Machine
8
+
9
+ alias_method :original_communicate, :communicate
10
+
11
+ def communicate
12
+ unless @communicator
13
+ if @config.vm.guest == :windows
14
+ @communicator = VagrantPlugins::VagrantHyperV::Communicator::PowerShell.new(self)
15
+ else
16
+ @communicator = original_communicate
17
+ end
18
+ end
19
+ @communicator
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,55 @@
1
+ #-------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Open Technologies, Inc.
3
+ # All Rights Reserved. Licensed under the Apache 2.0 License.
4
+ #--------------------------------------------------------------------------
5
+
6
+ require "#{Vagrant::source_root}/plugins/synced_folders/smb/synced_folder"
7
+
8
+ module VagrantPlugins
9
+ module SyncedFolderSMB
10
+ class SyncedFolder < Vagrant.plugin("2", :synced_folder)
11
+
12
+ alias_method :original_enable, :enable
13
+
14
+ def enable(machine, folders, nfsopts)
15
+ response = machine.provider.driver.get_host_ip
16
+ host_ip = response["host_ip"]
17
+ if machine.config.vm.guest == :windows
18
+ folders.each do |id, data|
19
+ machine.ui.output "#{data[:hostpath]} ==>"
20
+ machine.ui.output "\\\\#{host_ip}\\#{data[:smb_id]}"
21
+ end
22
+ guest_startup_script(machine, folders, host_ip)
23
+ else
24
+ original_enable(machine, folders, nfsopts)
25
+ end
26
+ end
27
+
28
+ def guest_startup_script(machine, folders, host_ip)
29
+ # Upload a startup script to VM,
30
+ # This script will authenticate the Network share with the host, and
31
+ # the guest can access the share path from a RDP session
32
+ file = Tempfile.new(['vagrant-smb-auth', '.ps1'])
33
+ begin
34
+ folders.each do |id, data|
35
+ smb_map_command = "New-SmbMapping"
36
+ smb_map_command += " -RemotePath \\\\#{host_ip}\\#{data[:smb_id]}"
37
+ smb_map_command += " -UserName #{@creds[:username]}"
38
+ smb_map_command += " -Password #{@creds[:password]}"
39
+ file.puts(smb_map_command)
40
+ end
41
+ file.fsync
42
+ file.close
43
+ ensure
44
+ file.close
45
+ end
46
+ machine.provider.driver.upload(file.path.to_s, "c:\\tmp\\vagrant-smb-auth.ps1")
47
+ # Invoke Remote Schedule task command in VM
48
+ command = 'schtasks /create /sc ONLOGON /tn vagrant-smb-auth /tr \"powershell c:\tmp\vagrant-smb-auth.ps1\"'
49
+ machine.provider.driver.run_remote_ps(command)
50
+ end
51
+
52
+ end
53
+ end
54
+ end
55
+
@@ -0,0 +1,37 @@
1
+ #-------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Open Technologies, Inc.
3
+ # All Rights Reserved. Licensed under the Apache 2.0 License.
4
+ #--------------------------------------------------------------------------
5
+
6
+ require "#{Vagrant::source_root}/lib/vagrant/util/which"
7
+ require "#{Vagrant::source_root}/lib/vagrant/util/subprocess"
8
+
9
+ module Vagrant
10
+ module Util
11
+ # Executes PowerShell scripts.
12
+ #
13
+ # This is primarily a convenience wrapper around Subprocess that
14
+ # properly sets powershell flags for you.
15
+ class PowerShell
16
+ # Monkey patch to fix a bug with Vagrant 1.5.1.
17
+ # https://github.com/mitchellh/vagrant/issues/3192.
18
+ # This has been fixed in 1.5.2. by
19
+ # https://github.com/jyggen/vagrant/commit/d7320399e2497aae9b9c3fa83d94b7210d21bfb5
20
+ def self.execute(path, *args, **opts, &block)
21
+ command = [
22
+ "powershell",
23
+ "-NoProfile",
24
+ "-ExecutionPolicy", "Bypass",
25
+ "&('#{path}')",
26
+ args
27
+ ].flatten
28
+
29
+ # Append on the options hash since Subprocess doesn't use
30
+ # Ruby 2.0 style options yet.
31
+ command << opts
32
+
33
+ Subprocess.execute(*command, &block)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,85 @@
1
+ #-------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Open Technologies, Inc.
3
+ # All Rights Reserved. Licensed under the Apache 2.0 License.
4
+ #--------------------------------------------------------------------------
5
+
6
+ # This is a sanity check to make sure no one is attempting to install
7
+ # this into an early Vagrant version.
8
+ if Vagrant::VERSION < "1.5.0"
9
+ raise "The Vagrant Hyper-V plugin is only compatible with Vagrant 1.5+"
10
+ end
11
+
12
+ module VagrantPlugins
13
+ module VagrantHyperV
14
+ class Plugin < Vagrant.plugin("2")
15
+ name "VagrantHyperV"
16
+ description <<-DESC
17
+ This plugin installs a provider that allows Vagrant to manage
18
+ windows guest machines in Hyper-V.
19
+ DESC
20
+
21
+ command "rdp" do
22
+ require_relative "command/rdp/command"
23
+ Command
24
+ end
25
+
26
+ provider(:hyperv) do
27
+ # Setup logging and i18n
28
+ # setup_logging
29
+ setup_i18n_hyperv
30
+
31
+ # Return the provider
32
+ require_relative "provider"
33
+ Provider
34
+ end
35
+
36
+ guest(:windows) do
37
+ require_relative "guest/windows"
38
+ Guest::Windows
39
+ end
40
+
41
+ guest_capability(:windows, :halt) do
42
+ require_relative "guest/cap/halt"
43
+ Guest::Cap::Halt
44
+ end
45
+
46
+
47
+
48
+ # This initializes the internationalization strings.
49
+ def self.setup_i18n_hyperv
50
+ I18n.load_path << File.expand_path("locales/en.yml", VagrantHyperV.source_root)
51
+ I18n.load_path << File.expand_path(
52
+ "templates/locales/providers_hyperv.yml", Vagrant.source_root)
53
+ I18n.reload!
54
+ end
55
+
56
+ # This sets up our log level to be whatever VAGRANT_LOG is.
57
+ def self.setup_logging
58
+ require "log4r"
59
+ level = nil
60
+ begin
61
+ level = Log4r.const_get(ENV["VAGRANT_LOG"].upcase)
62
+ rescue NameError
63
+ # This means that the logging constant wasn't found,
64
+ # which is fine. We just keep `level` as `nil`. But
65
+ # we tell the user.
66
+ level = nil
67
+ end
68
+
69
+ # Some constants, such as "true" resolve to booleans, so the
70
+ # above error checking doesn't catch it. This will check to make
71
+ # sure that the log level is an integer, as Log4r requires.
72
+ level = nil if !level.is_a?(Integer)
73
+
74
+ # Set the logging level on all "vagrant" namespaced
75
+ # logs as long as we have a valid level.
76
+ if level
77
+ logger = Log4r::Logger.new("vagrant_hyperv")
78
+ logger.outputters = Log4r::Outputter.stderr
79
+ logger.level = level
80
+ logger = nil
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end