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