vagrant-windows-hyperv 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/Gemfile +15 -0
- data/LICENSE.txt +7 -0
- data/README.md +89 -0
- data/Rakefile +29 -0
- data/example_box/metadata.json +1 -0
- data/lib/vagrant-windows-hyperv.rb +38 -0
- data/lib/vagrant-windows-hyperv/action.rb +81 -0
- data/lib/vagrant-windows-hyperv/action/export.rb +54 -0
- data/lib/vagrant-windows-hyperv/action/package.rb +21 -0
- data/lib/vagrant-windows-hyperv/action/rdp.rb +49 -0
- data/lib/vagrant-windows-hyperv/action/setup_package_files.rb +55 -0
- data/lib/vagrant-windows-hyperv/command/rdp/command.rb +22 -0
- data/lib/vagrant-windows-hyperv/communication/powershell.rb +37 -0
- data/lib/vagrant-windows-hyperv/driver.rb +89 -0
- data/lib/vagrant-windows-hyperv/errors.rb +31 -0
- data/lib/vagrant-windows-hyperv/guest/cap/halt.rb +19 -0
- data/lib/vagrant-windows-hyperv/guest/windows.rb +25 -0
- data/lib/vagrant-windows-hyperv/monkey_patch/action/provision.rb +32 -0
- data/lib/vagrant-windows-hyperv/monkey_patch/machine.rb +22 -0
- data/lib/vagrant-windows-hyperv/monkey_patch/plugins/synced_folders/smb/synced_folders.rb +55 -0
- data/lib/vagrant-windows-hyperv/monkey_patch/util/powershell.rb +37 -0
- data/lib/vagrant-windows-hyperv/plugin.rb +85 -0
- data/lib/vagrant-windows-hyperv/provider.rb +30 -0
- data/lib/vagrant-windows-hyperv/provisioner/chef_solo.rb +181 -0
- data/lib/vagrant-windows-hyperv/provisioner/puppet.rb +99 -0
- data/lib/vagrant-windows-hyperv/provisioner/shell.rb +81 -0
- data/lib/vagrant-windows-hyperv/scripts/check_winrm.ps1 +41 -0
- data/lib/vagrant-windows-hyperv/scripts/export_vm.ps1 +31 -0
- data/lib/vagrant-windows-hyperv/scripts/file_sync.ps1 +145 -0
- data/lib/vagrant-windows-hyperv/scripts/host_info.ps1 +25 -0
- data/lib/vagrant-windows-hyperv/scripts/hyperv_manager.ps1 +36 -0
- data/lib/vagrant-windows-hyperv/scripts/run_in_remote.ps1 +31 -0
- data/lib/vagrant-windows-hyperv/scripts/upload_file.ps1 +95 -0
- data/lib/vagrant-windows-hyperv/scripts/utils/create_session.ps1 +34 -0
- data/lib/vagrant-windows-hyperv/scripts/utils/write_messages.ps1 +18 -0
- data/lib/vagrant-windows-hyperv/version.rb +10 -0
- data/locales/en.yml +15 -0
- data/spec/hyper-v/config_spec.rb +36 -0
- data/spec/hyper-v/spec_helper.rb +9 -0
- data/templates/provisioners/chef-solo/solo.erb +51 -0
- data/vagrant-windows-hyperv.gemspec +63 -0
- data/vagrantfile_examples/Vagrantfile_linux +23 -0
- data/vagrantfile_examples/Vagrantfile_windows +24 -0
- 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
|