vagrant-windows-hyperv 1.0.1

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