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,30 @@
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/providers/hyperv/provider"
7
+
8
+ module VagrantPlugins
9
+ module VagrantHyperV
10
+ class Provider < VagrantPlugins::HyperV::Provider
11
+
12
+ def machine_id_changed
13
+ @driver = Driver.new(@machine)
14
+ end
15
+
16
+ def action(name)
17
+ # Attempt to get the action method from the Action class if it
18
+ # exists, otherwise return nil to show that we don't support the
19
+ # given action.
20
+ action_method = "action_#{name}"
21
+ if Action.respond_to?(action_method)
22
+ return Action.send(action_method)
23
+ else
24
+ super
25
+ end
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,181 @@
1
+ #-------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Open Technologies, Inc.
3
+ # All Rights Reserved. Licensed under the Apache 2.0 License.
4
+ #--------------------------------------------------------------------------
5
+
6
+ require "fileutils"
7
+ require "tempfile"
8
+
9
+ module VagrantPlugins
10
+ module VagrantHyperV
11
+ module Provisioner
12
+ class ChefSolo
13
+ attr_reader :provisioner
14
+ def initialize(env)
15
+ @env = env
16
+ @provisioner = env[:provisioner]
17
+ end
18
+
19
+ def provision_for_windows
20
+ # TODO
21
+ # Verify that the proper shared folders exist.
22
+
23
+ # Copy the chef cookbooks roles data bags and environment folders to Guest
24
+ copy_folder_to_guest(provisioner.cookbook_folders)
25
+ copy_folder_to_guest(provisioner.role_folders)
26
+ copy_folder_to_guest(provisioner.data_bags_folders)
27
+ copy_folder_to_guest(provisioner.environments_folders)
28
+
29
+ # Upload Encrypted data bag
30
+ upload_encrypted_data_bag_secret if config.encrypted_data_bag_secret_key_path
31
+ setup_json
32
+ setup_solo_config
33
+ run_chef_solo
34
+ delete_encrypted_data_bag_secret
35
+ end
36
+
37
+ def setup_json
38
+ @env[:machine].env.ui.info I18n.t("vagrant.provisioners.chef.json")
39
+
40
+ # Get the JSON that we're going to expose to Chef
41
+ json = config.json
42
+ json[:run_list] = config.run_list if !config.run_list.empty?
43
+ json = JSON.pretty_generate(json)
44
+
45
+ # Create a temporary file to store the data so we
46
+ # can upload it
47
+ temp = Tempfile.new("vagrant")
48
+ temp.write(json)
49
+ temp.close
50
+
51
+ remote_file = File.join(config.provisioning_path, "dna.json")
52
+ @env[:machine].provider.driver.upload(temp.path, remote_file)
53
+ end
54
+
55
+ def setup_solo_config
56
+ cookbooks_path = guest_paths(provisioner.cookbook_folders)
57
+ roles_path = guest_paths(provisioner.role_folders)
58
+ data_bags_path = guest_paths(provisioner.data_bags_folders).first
59
+ environments_path = guest_paths(provisioner.environments_folders).first
60
+ source_path = "#{VagrantPlugins::VagrantHyperV.source_root}"
61
+ template_path = source_path + "/templates/provisioners/chef-solo/solo"
62
+ setup_config(template_path, "solo.rb", {
63
+ :cookbooks_path => cookbooks_path,
64
+ :recipe_url => config.recipe_url,
65
+ :roles_path => roles_path,
66
+ :data_bags_path => data_bags_path,
67
+ :environments_path => environments_path
68
+ })
69
+ end
70
+
71
+ def setup_config(template, filename, template_vars)
72
+ # If we have custom configuration, upload it
73
+ remote_custom_config_path = nil
74
+ if config.custom_config_path
75
+ expanded = File.expand_path(
76
+ config.custom_config_path, @machine.env.root_path)
77
+ remote_custom_config_path = File.join(
78
+ config.provisioning_path, "custom-config.rb")
79
+
80
+ @env[:machine].provider.driver.upload(expanded, remote_custom_config_path)
81
+ end
82
+
83
+ config_file = Vagrant::Util::TemplateRenderer.render(template, {
84
+ :custom_configuration => remote_custom_config_path,
85
+ :file_cache_path => config.file_cache_path,
86
+ :file_backup_path => config.file_backup_path,
87
+ :log_level => config.log_level.to_sym,
88
+ :verbose_logging => config.verbose_logging,
89
+ :http_proxy => config.http_proxy,
90
+ :http_proxy_user => config.http_proxy_user,
91
+ :http_proxy_pass => config.http_proxy_pass,
92
+ :https_proxy => config.https_proxy,
93
+ :https_proxy_user => config.https_proxy_user,
94
+ :https_proxy_pass => config.https_proxy_pass,
95
+ :no_proxy => config.no_proxy,
96
+ :formatter => config.formatter
97
+ }.merge(template_vars))
98
+
99
+ # Create a temporary file to store the data so we
100
+ # can upload it
101
+ temp = Tempfile.new("vagrant")
102
+ temp.write(config_file)
103
+ temp.close
104
+
105
+ remote_file = File.join(config.provisioning_path, filename)
106
+ @env[:machine].provider.driver.upload(temp.path, remote_file)
107
+ end
108
+
109
+ def run_chef_solo
110
+ if config.run_list && config.run_list.empty?
111
+ @env[:machine].ui.warn(I18n.t("vagrant.chef_run_list_empty"))
112
+ end
113
+
114
+ options = [
115
+ "-c #{config.provisioning_path}/solo.rb",
116
+ "-j #{config.provisioning_path}/dna.json"
117
+ ]
118
+
119
+ command_env = config.binary_env ? "#{config.binary_env} " : ""
120
+ command_args = config.arguments ? " #{config.arguments}" : ""
121
+ command = "#{command_env}#{chef_binary_path("chef-solo")} " +
122
+ "#{options.join(" ")} #{command_args}"
123
+ config.attempts.times do |attempt|
124
+ if attempt == 0
125
+ @env[:machine].env.ui.info I18n.t("vagrant.provisioners.chef.running_solo")
126
+ else
127
+ @env[:machine].env.ui.info I18n.t("vagrant.provisioners.chef.running_solo_again")
128
+ end
129
+
130
+ @env[:machine].provider.driver.run_remote_ps(command) do |type, data|
131
+ # Output the data with the proper color based on the stream.
132
+ if (type == :stdout || type == :stderr)
133
+ @env[:ui].detail data
134
+ end
135
+ end
136
+ end
137
+
138
+ end
139
+
140
+ def delete_encrypted_data_bag_secret
141
+ # Run remote command to delete
142
+ # config.encrypted_data_bag_secret
143
+ end
144
+
145
+ def upload_encrypted_data_bag_secret
146
+ @machine.env.ui.info I18n.t("vagrant.provisioners.chef.upload_encrypted_data_bag_secret_key")
147
+ @env[:machine].provider.driver.upload(encrypted_data_bag_secret_key_path,
148
+ config.encrypted_data_bag_secret)
149
+ end
150
+
151
+ def encrypted_data_bag_secret_key_path
152
+ File.expand_path(config.encrypted_data_bag_secret_key_path, @env[:machine].env.root_path)
153
+ end
154
+
155
+ def config
156
+ provisioner.config
157
+ end
158
+
159
+ def guest_paths(folders)
160
+ folders.map { |parts| parts[2] }
161
+ end
162
+
163
+ # Returns the path to the Chef binary, taking into account the
164
+ # `binary_path` configuration option.
165
+ def chef_binary_path(binary)
166
+ return binary if !config.binary_path
167
+ return File.join(config.binary_path, binary)
168
+ end
169
+
170
+ def copy_folder_to_guest(folders)
171
+ folders.each do |type, local_path, remote_path|
172
+ if type == :host
173
+ @env[:machine].provider.driver.upload(local_path, remote_path)
174
+ end
175
+ end
176
+ end
177
+
178
+ end
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,99 @@
1
+ #-------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Open Technologies, Inc.
3
+ # All Rights Reserved. Licensed under the Apache 2.0 License.
4
+ #--------------------------------------------------------------------------
5
+
6
+ require "fileutils"
7
+ require "tempfile"
8
+
9
+ module VagrantPlugins
10
+ module VagrantHyperV
11
+ module Provisioner
12
+ class Puppet
13
+ attr_reader :provisioner
14
+ def initialize(env)
15
+ @env = env
16
+ @provisioner = env[:provisioner]
17
+ end
18
+
19
+ def provision_for_windows
20
+
21
+ options = [config.options].flatten
22
+ @module_paths = provisioner.instance_variable_get("@module_paths")
23
+ @hiera_config_path = provisioner.instance_variable_get("@hiera_config_path")
24
+ @manifest_file = provisioner.instance_variable_get("@manifest_file")
25
+
26
+ # Copy the manifests directory to the guest
27
+ if config.manifests_path[0].to_sym == :host
28
+ @env[:machine].provider.driver.upload(
29
+ File.expand_path(config.manifests_path[1], @env[:machine].env.root_path),
30
+ provisioner.manifests_guest_path)
31
+ end
32
+
33
+ # Copy the module paths to the guest
34
+ @module_paths.each do |from, to|
35
+ @env[:machine].provider.driver.upload(from, to)
36
+ end
37
+
38
+
39
+ module_paths = @module_paths.map { |_, to| to }
40
+ if !@module_paths.empty?
41
+ # Prepend the default module path
42
+ module_paths.unshift("/ProgramData/PuppetLabs/puppet/etc/modules")
43
+
44
+ # Add the command line switch to add the module path
45
+ options << "--modulepath '#{module_paths.join(':')}'"
46
+ end
47
+
48
+ if @hiera_config_path
49
+ options << "--hiera_config=#{@hiera_config_path}"
50
+
51
+ # Upload Hiera configuration if we have it
52
+ local_hiera_path = File.expand_path(config.hiera_config_path,
53
+ @env[:machine].env.root_path)
54
+ @env[:machine].provider.driver.upload(local_hiera_path, @hiera_config_path)
55
+ end
56
+
57
+ options << "--manifestdir #{provisioner.manifests_guest_path}"
58
+ options << "--detailed-exitcodes"
59
+ options << @manifest_file
60
+ options = options.join(" ")
61
+
62
+ # Build up the custom facts if we have any
63
+ facter = ""
64
+ if !config.facter.empty?
65
+ facts = []
66
+ config.facter.each do |key, value|
67
+ facts << "FACTER_#{key}='#{value}'"
68
+ end
69
+
70
+ facter = "#{facts.join(" ")} "
71
+ end
72
+
73
+ command = "#{facter}puppet apply #{options}"
74
+ if config.working_directory
75
+ command = "cd #{config.working_directory} && #{command}"
76
+ end
77
+
78
+ @env[:ui].info I18n.t("vagrant.provisioners.puppet.running_puppet",
79
+ :manifest => config.manifest_file)
80
+
81
+ @env[:ui].info "Executing puppet script in Guest"
82
+ @env[:machine].provider.driver.run_remote_ps(command) do |type, data|
83
+ # Output the data with the proper color based on the stream.
84
+ if (type == :stdout || type == :stderr)
85
+ @env[:ui].detail data
86
+ end
87
+ end
88
+ end
89
+
90
+ protected
91
+
92
+ def config
93
+ provisioner.config
94
+ end
95
+
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,81 @@
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 Provisioner
9
+ class Shell
10
+ attr_reader :provisioner
11
+ def initialize(env)
12
+ @env = env
13
+ @provisioner = env[:provisioner]
14
+ end
15
+
16
+ def provision_for_windows
17
+ arguments = ""
18
+ arguments = " #{config.args}" if config.args
19
+ with_windows_script_file do |path|
20
+
21
+ guest_path = if File.extname(config.upload_path) == ""
22
+ "#{config.upload_path}#{File.extname(path.to_s)}"
23
+ else
24
+ config.upload_path
25
+ end
26
+
27
+ response = @env[:machine].provider.driver.upload(path, guest_path)
28
+
29
+ command = "powershell.exe #{guest_path} #{arguments}"
30
+ @env[:machine].provider.driver.run_remote_ps(command) do |type, data|
31
+ if type == :stdout || type == :stderr
32
+ @env[:ui].detail data
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ protected
39
+
40
+ def config
41
+ provisioner.config
42
+ end
43
+
44
+ # This method yields the path to a script to upload and execute
45
+ # on the remote server. This method will properly clean up the
46
+ # script file if needed.
47
+ def with_windows_script_file
48
+ if config.remote?
49
+ download_path = @env[:machine].env.tmp_path.join("#{@env[:machine].id}-remote-script#{File.extname(config.path)}")
50
+ download_path.delete if download_path.file?
51
+
52
+ begin
53
+ Vagrant::Util::Downloader.new(config.path, download_path).download!
54
+ yield download_path
55
+ ensure
56
+ download_path.delete
57
+ end
58
+
59
+ elsif config.path
60
+ # Just yield the path to that file...
61
+ yield config.path
62
+ else
63
+ # Otherwise we have an inline script, we need to Tempfile it,
64
+ # and handle it specially...
65
+ file = Tempfile.new(['vagrant-powershell', '.ps1'])
66
+
67
+ begin
68
+ file.write(config.inline)
69
+ file.fsync
70
+ file.close
71
+ yield file.path
72
+ ensure
73
+ file.close
74
+ end
75
+ end
76
+ end
77
+
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,41 @@
1
+ #-------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Open Technologies, Inc.
3
+ # All Rights Reserved. Licensed under the Apache 2.0 License.
4
+ #--------------------------------------------------------------------------
5
+ param (
6
+ [string]$guest_ip = $(throw "-guest_ip is required."),
7
+ [string]$username = $(throw "-guest_username is required."),
8
+ [string]$password = $(throw "-guest_password is required.")
9
+ )
10
+
11
+ # Include the following modules
12
+ $presentDir = Split-Path -parent $PSCommandPath
13
+ . ([System.IO.Path]::Combine($presentDir, "utils\write_messages.ps1"))
14
+ . ([System.IO.Path]::Combine($presentDir, "utils\create_session.ps1"))
15
+
16
+ try {
17
+ $response = Create-Remote-Session $guest_ip $username $password
18
+ if (!$response["session"] -and $response["error"]) {
19
+ Write-Host $response["error"]
20
+ return
21
+ }
22
+ function Remote-Execute() {
23
+ $winrm_state = ""
24
+ get-service winrm | ForEach-Object {
25
+ $winrm_state = $_.status
26
+ }
27
+ return "$winrm_state"
28
+ }
29
+ $result = Invoke-Command -Session $response["session"] -ScriptBlock ${function:Remote-Execute} -ErrorAction "stop"
30
+ $resultHash = @{
31
+ message = "$result"
32
+ }
33
+ Write-Output-Message $resultHash
34
+ } catch {
35
+ $errortHash = @{
36
+ type = "PowerShellError"
37
+ error ="Failed to copy file $_"
38
+ }
39
+ Write-Error-Message $errortHash
40
+ return
41
+ }
@@ -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
+ param (
7
+ [string]$vm_id = $(throw "-vm_id is required."),
8
+ [string]$path = $(throw "-path is required.")
9
+ )
10
+
11
+ # Include the following modules
12
+ $presentDir = Split-Path -parent $PSCommandPath
13
+ . ([System.IO.Path]::Combine($presentDir, "utils\write_messages.ps1"))
14
+
15
+
16
+ # Export the Virtual Machine
17
+ try {
18
+ $vm = Get-Vm -Id $vm_id
19
+ $vm | Export-VM -Path $path -ErrorAction "stop"
20
+ $name = $vm.name
21
+ $resultHash = @{
22
+ name = "$name"
23
+ }
24
+ Write-Output-Message $resultHash
25
+ } catch {
26
+ $errortHash = @{
27
+ type = "PowerShellError"
28
+ error = "Failed to export a VM $_"
29
+ }
30
+ Write-Error-Message $errortHash
31
+ }