realityforge-vagrant-windows 0.1.4

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.
@@ -0,0 +1,9 @@
1
+ *.gem
2
+ *.rbc
3
+ Gemfile.lock
4
+ pkg
5
+ rdoc
6
+ # IntelliJ project files
7
+ /*.iml
8
+ /*.ipr
9
+ /*.iws
@@ -0,0 +1 @@
1
+ 1.9.3-p327
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in my_gem.gemspec
4
+ gemspec
5
+
@@ -0,0 +1,115 @@
1
+ TODO:
2
+ vagrant rdp && vagrant ps to connect to VM
3
+
4
+
5
+ Installing
6
+ ==========
7
+
8
+ ```
9
+ gem install vagrant-windows
10
+ ```
11
+
12
+ Building a Base Box
13
+ ===================
14
+
15
+ All Windows Machines
16
+ --------------------
17
+ -Enable WinRM
18
+
19
+ ```
20
+ winrm quickconfig -q
21
+ winrm set winrm/config/winrs @{MaxMemoryPerShellMB="512"}
22
+ winrm set winrm/config @{MaxTimeoutms="1800000"}
23
+ winrm set winrm/config/service @{AllowUnencrypted="true"}
24
+ winrm set winrm/config/service/auth @{Basic="true"}
25
+ ```
26
+ - Create a vagrant user
27
+ - For things to work out of the box, username and password should both be vagrant
28
+
29
+ - Turn off UAC (Msconfig)
30
+ - Disable complex passwords
31
+
32
+ Servers
33
+ --------
34
+ - Disable Shutdown Tracker (http://www.jppinto.com/2010/01/how-to-disable-the-shutdown-event-tracker-in-server-20032008/)
35
+ - Disable "Server Manager" Starting at login (http://www.elmajdal.net/win2k8/How_to_Turn_Off_The_Automatic_Display_of_Server_Manager_At_logon.aspx)
36
+
37
+ The Vagrant File
38
+ ================
39
+
40
+ Add the following to your Vagrantfile
41
+
42
+ ```ruby
43
+ config.vm.guest = :windows
44
+
45
+ config.vm.forward_port 3389, 3390, :name => "rdp", :auto => true
46
+ config.vm.forward_port 5985, 5985, :name => "winrm", :auto => true
47
+ ```
48
+
49
+ Example:
50
+ ```ruby
51
+ Vagrant::Config.run do |config|
52
+
53
+ #The following timeout configuration is option, however if have
54
+ #any large remote_file resources in your chef recipes, you may
55
+ #experience timeouts (reported as 500 responses)
56
+ config.winrm.timeout = 1800 #Set WinRM Timeout in seconds (Default 30)
57
+
58
+ # Configure base box parameters
59
+ config.vm.box = "windows2008r2"
60
+ config.vm.box_url = "./windows-2008-r2.box"
61
+ config.vm.guest = :windows
62
+
63
+ config.vm.forward_port 3389, 3390, :name => "rdp", :auto => true
64
+ config.vm.forward_port 5985, 5985, :name => "winrm", :auto => true
65
+
66
+ config.vm.provision :chef_solo do |chef|
67
+ chef.add_recipe("your::recipe")
68
+ end
69
+
70
+ end
71
+ ````
72
+
73
+ What Works?
74
+ ===========
75
+ - vagrant up|hault|reload|provision
76
+ - Chef Vagrant Provisioner
77
+ - Puppet standalone provisioning
78
+
79
+ What has not been tested
80
+ ========================
81
+ - Everything Else!!!
82
+ - Shell provisioning
83
+ - Shell should work, though I have not vetted it yet.
84
+
85
+ What does not work
86
+ ==================
87
+ - <s>Complex networking setups</s> - Fixed in 0.0.3
88
+ - Note that I have not tested the Virtual Box 4.0 Driver, all _should_ work. Can someone please confirm?
89
+
90
+ What Can I do to help?
91
+ ======================
92
+ 1. Contribute Code (See Below)
93
+ 2. Test Various Scenarios and file bugs for things that dont work
94
+
95
+ Contributing
96
+ ============
97
+ 1. Fork it.
98
+ 2. Create a branch (git checkout -b my_feature_branch)
99
+ 3. Commit your changes (git commit -am "Added a sweet feature")
100
+ 4. Push to the branch (git push origin my_feature_branch)
101
+ 5. Create a pull requst from your branch into master (Please be sure to provide enough detail for us to cipher what this change is doing)
102
+
103
+
104
+ References and Shout Outs
105
+ =========================
106
+ - Chris McClimans - Vagrant Branch (https://github.com/hh/vagrant/blob/feature/winrm/)
107
+ -Dan Wanek - WinRM GEM (https://github.com/zenchild/WinRM)
108
+ - +1 For being super responsive to pull requests.
109
+
110
+
111
+ Changelog
112
+ =========
113
+ 0.1.1 - Remove extra debug information from command output.
114
+ 0.1.2 - added virtual box 4.2 support
115
+ 0.1.3 - added puppet provisioner
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,185 @@
1
+ require 'timeout'
2
+
3
+ require 'log4r'
4
+ #require 'em-winrm'
5
+ require 'winrm'
6
+ require 'highline'
7
+
8
+ require 'vagrant/util/ansi_escape_code_remover'
9
+ require 'vagrant/util/file_mode'
10
+ require 'vagrant/util/platform'
11
+ require 'vagrant/util/retryable'
12
+
13
+ module Vagrant
14
+ module Communication
15
+ # Provides communication with the VM via WinRM.
16
+ class WinRM < Base
17
+
18
+ include Util::ANSIEscapeCodeRemover
19
+ include Util::Retryable
20
+
21
+ attr_reader :logger
22
+ attr_reader :vm
23
+
24
+ def initialize(vm)
25
+ @vm = vm
26
+ @logger = Log4r::Logger.new("vagrant::communication::winrm")
27
+ @co = nil
28
+ end
29
+
30
+ def ready?
31
+ logger.debug("Checking whether WinRM is ready...")
32
+
33
+ Timeout.timeout(@vm.config.winrm.timeout) do
34
+ execute "hostname"
35
+ end
36
+
37
+ # If we reached this point then we successfully connected
38
+ logger.info("WinRM is ready!")
39
+ true
40
+ rescue Timeout::Error, HTTPClient::KeepAliveDisconnected => e
41
+ #, Errors::SSHConnectionRefused, Net::SSH::Disconnect => e
42
+ # The above errors represent various reasons that WinRM may not be
43
+ # ready yet. Return false.
44
+ logger.info("WinRM not up yet: #{e.inspect}")
45
+
46
+ return false
47
+ end
48
+
49
+ # Wrap Sudo in execute.... One day we could integrate with UAC, but Icky
50
+ def sudo(command, opts=nil, &block)
51
+ execute(command,opts,&block)
52
+ end
53
+
54
+ def execute(command, opts=nil, &block)
55
+
56
+ # Connect to WinRM, giving it a few tries
57
+ logger.info("Connecting to WinRM: #{@vm.winrm.info[:host]}:#{@vm.winrm.info[:port]}")
58
+
59
+ opts = {
60
+ :error_check => true,
61
+ :error_class => Errors::VagrantError,
62
+ :error_key => :winrm_bad_exit_status,
63
+ :command => command,
64
+ :sudo => false,
65
+ :shell => :powershell
66
+ }.merge(opts || {})
67
+
68
+ # Connect via WinRM and execute the command in the shell.
69
+ exceptions = [HTTPClient::KeepAliveDisconnected]
70
+ exit_status = retryable(:tries => @vm.config.winrm.max_tries, :on => exceptions, :sleep => 10) do
71
+ logger.debug "WinRM Trying to connect"
72
+ shell_execute(command,opts[:shell], &block)
73
+ end
74
+
75
+ logger.debug("#{command} EXIT STATUS #{exit_status.inspect}")
76
+
77
+ # Check for any errors
78
+ if opts[:error_check] && exit_status != 0
79
+ # The error classes expect the translation key to be _key,
80
+ # but that makes for an ugly configuration parameter, so we
81
+ # set it here from `error_key`
82
+ error_opts = opts.merge(:_key => opts[:error_key])
83
+ raise opts[:error_class], error_opts
84
+ end
85
+
86
+ # Return the exit status
87
+ exit_status
88
+ end
89
+
90
+ def new_session
91
+ opts = {
92
+ :user => vm.config.winrm.username,
93
+ :pass => vm.config.winrm.password,
94
+ :host => vm.config.winrm.host,
95
+ :port => vm.winrm.info[:port],
96
+ :operation_timeout => vm.config.winrm.timeout,
97
+ :basic_auth_only => true
98
+ }.merge ({})
99
+
100
+ # create a session
101
+ logger.info("Attempting WinRM session with options: #{opts}")
102
+ begin
103
+ endpoint = "http://#{opts[:host]}:#{opts[:port]}/wsman"
104
+ client = ::WinRM::WinRMWebService.new(endpoint, :plaintext, opts)
105
+ client.set_timeout(opts[:operation_timeout]) if opts[:operation_timeout]
106
+ rescue ::WinRM::WinRMAuthorizationError => error
107
+ raise ::WinRM::WinRMAuthorizationError.new("#{error.message}@#{opts[:host]}")
108
+ end
109
+
110
+ client
111
+ end
112
+
113
+ def session
114
+ @session ||= new_session
115
+ end
116
+
117
+ def h
118
+ @highline ||= HighLine.new
119
+ end
120
+
121
+ def print_data(data, color = :green)
122
+ if data =~ /\n/
123
+ data.split(/\n/).each { |d| print_data(d, color) }
124
+ else
125
+ puts h.color(data.chomp, color)
126
+ end
127
+ end
128
+
129
+ def upload(from, to)
130
+ file = "winrm-upload-#{rand()}"
131
+ file_name = (session.cmd("echo %TEMP%\\#{file}"))[:data][0][:stdout].chomp
132
+ session.powershell <<-EOH
133
+ if(Test-Path #{to})
134
+ {
135
+ rm #{to}
136
+ }
137
+ EOH
138
+ Base64.encode64(IO.binread(from)).gsub("\n",'').chars.to_a.each_slice(8000-file_name.size) do |chunk|
139
+ out = session.cmd( "echo #{chunk.join} >> \"#{file_name}\"" )
140
+ end
141
+ execute "mkdir [System.IO.Path]::GetDirectoryName(\"#{to}\")"
142
+ execute <<-EOH
143
+ $base64_string = Get-Content \"#{file_name}\"
144
+ $bytes = [System.Convert]::FromBase64String($base64_string)
145
+ $new_file = [System.IO.Path]::GetFullPath(\"#{to}\")
146
+ [System.IO.File]::WriteAllBytes($new_file,$bytes)
147
+ EOH
148
+ end
149
+
150
+ protected
151
+
152
+ # Executes the command on an SSH connection within a login shell.
153
+ def shell_execute(command,shell = :powershell)
154
+ logger.info("Execute: #{command}")
155
+ exit_status = nil
156
+
157
+ if shell.eql? :cmd
158
+ output = session.cmd(command) do |out,error|
159
+ print_data(out) if out
160
+ print_data(error, :red) if error
161
+ end
162
+ elsif shell.eql? :powershell
163
+ new_command = File.read(File.expand_path("#{File.dirname(__FILE__)}/../scripts/command_alias.ps1"))
164
+ new_command << "\r\n"
165
+ new_command << command
166
+ output = session.powershell(new_command) do |out,error|
167
+ print_data(out) if out
168
+ print_data(error, :red) if error
169
+ end
170
+ else
171
+ raise Vagrant::Errors::WinRMInvalidShell, "#{shell} is not a valid type of shell"
172
+ end
173
+
174
+
175
+ exit_status = output[:exitcode]
176
+ logger.debug exit_status.inspect
177
+
178
+ # Return the final exit status
179
+ return exit_status
180
+ rescue ::WinRM::WinRMHTTPTransportError => e
181
+ raise Vagrant::Errors::WinRMTimeout, e.message
182
+ end
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,27 @@
1
+ module Vagrant
2
+ module Config
3
+ class Windows < Vagrant::Config::Base
4
+ attr_accessor :winrm_user
5
+ attr_accessor :winrm_password
6
+ attr_accessor :halt_timeout
7
+ attr_accessor :halt_check_interval
8
+ attr_accessor :device
9
+
10
+ def initialize
11
+ @winrm_user = 'vagrant'
12
+ @winrm_password = 'vagrant'
13
+ @halt_timeout = 30
14
+ @halt_check_interval = 1
15
+ @device = "e1000g"
16
+ end
17
+
18
+ def validate(env, errors)
19
+ [ :winrm_user, :winrm_password].each do |field|
20
+ errors.add(I18n.t("vagrant.config.common.error_empty", :field => field)) if !instance_variable_get("@#{field}".to_sym)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ Vagrant.config_keys.register(:windows) { Vagrant::Config::Windows }
@@ -0,0 +1,31 @@
1
+ module Vagrant
2
+ module Config
3
+ class WinRM < Vagrant::Config::Base
4
+ attr_accessor :username
5
+ attr_accessor :password
6
+ attr_accessor :host
7
+ attr_accessor :port
8
+ attr_accessor :guest_port
9
+ attr_accessor :max_tries
10
+ attr_accessor :timeout
11
+
12
+ def initialize
13
+ @username = "vagrant"
14
+ @password = "vagrant"
15
+ @guest_port = 5985
16
+ @host = "localhost"
17
+ @max_tries = 12
18
+ @timeout = 1800
19
+ end
20
+
21
+ def validate(env, errors)
22
+ [:username, :password, :host, :max_tries, :timeout].each do |field|
23
+ errors.add(I18n.t("vagrant.config.common.error_empty", :field => field)) if !instance_variable_get("@#{field}".to_sym)
24
+ end
25
+
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ Vagrant.config_keys.register(:winrm) { Vagrant::Config::WinRM }
@@ -0,0 +1,22 @@
1
+ module Vagrant
2
+ module Errors
3
+ class WinRMPortNotDetected < VagrantError
4
+ status_code(550)
5
+ error_key(:winrm_port_not_detected)
6
+ end
7
+
8
+ class WinRMInvalidShell < VagrantError
9
+ status_code(551)
10
+ error_key(:winrm_invalid_shell)
11
+ end
12
+ class WinRMTransferError < VagrantError
13
+ status_code(552)
14
+ error_key(:winrm_upload_error)
15
+ end
16
+ class WinRMTimeout < VagrantError
17
+ status_code(553)
18
+ error_key(:winrm_timeout)
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,116 @@
1
+ module Vagrant
2
+ module Guest
3
+ # A general Vagrant system implementation for "windows".
4
+ #
5
+ # Contributed by Chris McClimans <chris@hippiehacker.org>
6
+ class Windows < Base
7
+ # A custom config class which will be made accessible via `config.windows`
8
+ # Here for whenever it may be used.
9
+ class WindowsError < Errors::VagrantError
10
+ error_namespace("vagrant.guest.windows")
11
+ end
12
+
13
+ def change_host_name(name)
14
+ #### on windows, renaming a computer seems to require a reboot
15
+ @vm.channel.session.cmd("netdom renamecomputer %COMPUTERNAME% /force /reb:2 /newname:#{name}")
16
+ sleep 5
17
+ wait_for_state :running, @vm.config.windows.halt_timeout, @vm.config.windows.halt_check_interval
18
+ end
19
+
20
+ # TODO: I am sure that ciphering windows versions will be important at some point
21
+ def distro_dispatch
22
+ :windows
23
+ end
24
+
25
+ def halt
26
+ @vm.channel.execute("shutdown /s /t 1 /c \"Vagrant Halt\" /f /d p:4:1")
27
+ # Wait until the VM's state is actually powered off. If this doesn't
28
+ # occur within a reasonable amount of time (15 seconds by default),
29
+ # then simply return and allow Vagrant to kill the machine.
30
+ wait_for_state :poweroff, @vm.config.windows.halt_timeout, @vm.config.windows.halt_check_interval
31
+ end
32
+
33
+ def wait_for_state(state, timeout, interval)
34
+ count = 0
35
+ while @vm.state != state
36
+ count += 1
37
+ return if count > timeout
38
+ sleep interval
39
+ end
40
+ end
41
+
42
+ def mount_shared_folder(name, guestpath, options)
43
+ mount_script = TemplateRenderer.render(File.expand_path("#{File.dirname(__FILE__)}/../scripts/mount_volume.ps1"),
44
+ :options => {:mount_point => guestpath, :name => name})
45
+ @vm.channel.execute(mount_script,{:shell => :powershell})
46
+ end
47
+
48
+ def mount_nfs(ip, folders)
49
+ raise NotImplementedError, "Mounting NFS Shares on windows is not implemented"
50
+ # TODO: Maybe check for nfs support on the guest, since its often
51
+ # not installed by default
52
+ #folders.each do |name, opts|
53
+ # # Expand the guestpath, so we can handle things like "~/vagrant"
54
+ # real_guestpath = expanded_guest_path(opts[:guestpath])
55
+
56
+ # Do the actual creating and mounting
57
+ # @vm.channel.sudo("mkdir -p #{real_guestpath}")
58
+ # @vm.channel.sudo("mount -o vers=#{opts[:nfs_version]} #{ip}:'#{opts[:hostpath]}' #{real_guestpath}",
59
+ # :error_class => LinuxError,
60
+ # :error_key => :mount_nfs_fail)
61
+ #end
62
+ end
63
+
64
+ def configure_networks(networks)
65
+ ### HACK!!!!!
66
+ Nori.advanced_typecasting = false
67
+ if driver_mac_address = @vm.driver.read_mac_addresses
68
+ driver_mac_address = driver_mac_address.invert
69
+ end
70
+
71
+ vm_interface_map = {}
72
+ @vm.channel.session.wql("SELECT * FROM Win32_NetworkAdapter WHERE NetConnectionStatus=2")[:win32_network_adapter].each do |nic|
73
+ naked_mac = nic[:mac_address].gsub(':','')
74
+
75
+ if driver_mac_address[naked_mac]
76
+ vm_interface_map[driver_mac_address[naked_mac]] = {
77
+ :name => nic[:net_connection_id],
78
+ :mac_address => naked_mac,
79
+ :index => nic[:interface_index]
80
+ }
81
+ end
82
+ end
83
+ networks.each do |network|
84
+ interface_name = vm_interface_map[network[:interface]+1][:name]
85
+ interface_index = vm_interface_map[network[:interface]+1][:index]
86
+
87
+ if network[:type].to_sym == :static
88
+ @vm.channel.execute("netsh interface ip set address \"#{interface_name}\" static #{network[:ip]} #{network[:netmask]}")
89
+
90
+ elsif network[:type].to_sym == :dhcp
91
+
92
+ if !vm.channel.test("if (-not (netsh interface ip show address \"#{interface_name}\" | where \{$_ -match \"DHCP enabled:\s+Yes\"\})) \{exit 1\} ")
93
+ vm.channel.execute("netsh interface ip set address \"#{interface_name}\" dhcp")
94
+ end
95
+ end
96
+ end
97
+ end
98
+
99
+
100
+ def windows_path(path)
101
+ p = ''
102
+ if path =~ /^\//
103
+ p << 'C:\\'
104
+ end
105
+ p << path
106
+ p.gsub! /\//, "\\"
107
+ p.gsub /\\\\{0,}/, "\\"
108
+ end
109
+
110
+
111
+
112
+ end
113
+ end
114
+ end
115
+
116
+ Vagrant.guests.register(:windows) { Vagrant::Guest::Windows }
@@ -0,0 +1,57 @@
1
+ require 'vagrant/driver/virtualbox_base'
2
+ require 'vagrant/driver/virtualbox'
3
+
4
+
5
+ module Vagrant
6
+ module Driver
7
+
8
+ class VirtualBox_4_2 < VirtualBoxBase
9
+ def read_mac_addresses
10
+ macs = {}
11
+ info = execute("showvminfo", @uuid, "--machinereadable", :retryable => true)
12
+ info.split("\n").each do |line|
13
+ if matcher = /^macaddress(\d+)="(.+?)"$/.match(line)
14
+ adapter = matcher[1].to_i
15
+ mac = matcher[2].to_s
16
+ macs[adapter] = mac
17
+ end
18
+ end
19
+ macs
20
+ end
21
+ end
22
+
23
+ class VirtualBox_4_1 < VirtualBoxBase
24
+ def read_mac_addresses
25
+ macs = {}
26
+ info = execute("showvminfo", @uuid, "--machinereadable", :retryable => true)
27
+ info.split("\n").each do |line|
28
+ if matcher = /^macaddress(\d+)="(.+?)"$/.match(line)
29
+ adapter = matcher[1].to_i
30
+ mac = matcher[2].to_s
31
+ macs[adapter] = mac
32
+ end
33
+ end
34
+ macs
35
+ end
36
+ end
37
+
38
+ class VirtualBox_4_0 < VirtualBoxBase
39
+ def read_mac_addresses
40
+ macs = {}
41
+ info = execute("showvminfo", @uuid, "--machinereadable", :retryable => true)
42
+ info.split("\n").each do |line|
43
+ if matcher = /^macaddress(\d+)="(.+?)"$/.match(line)
44
+ adapter = matcher[1].to_i
45
+ mac = matcher[2].to_s
46
+ macs[adapter] = mac
47
+ end
48
+ end
49
+ macs
50
+ end
51
+ end
52
+
53
+ class VirtualBox < VirtualBoxBase
54
+ def_delegator :@driver, :read_mac_addresses
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,16 @@
1
+ module Vagrant
2
+ class VM
3
+ def winrm
4
+ @winrm ||= WinRM.new(self)
5
+ end
6
+
7
+ def channel
8
+ if @guest.class.eql? Vagrant::Guest::Windows
9
+ @channel ||= Communication::WinRM.new(self)
10
+ else
11
+ @channel ||= Communication::SSH.new(self)
12
+ end
13
+ @channel
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,72 @@
1
+ module Vagrant
2
+ module Provisioners
3
+ class Puppet < Base
4
+ def run_puppet_client
5
+ options = [config.options].flatten
6
+ if env[:vm].config.vm.guest == :windows
7
+ options << "--modulepath '#{@module_paths.values.join(';')}'" if !@module_paths.empty?
8
+ else
9
+ options << "--modulepath '#{@module_paths.values.join(':')}'" if !@module_paths.empty?
10
+ end
11
+
12
+ options << @manifest_file
13
+ options = options.join(" ")
14
+
15
+ # Build up the custom facts if we have any
16
+ facter = ""
17
+ if !config.facter.empty?
18
+ facts = []
19
+ config.facter.each do |key, value|
20
+ if env[:vm].config.vm.guest == :windows
21
+ facts << "$env:FACTER_#{key}='#{value}';"
22
+ else
23
+ facts << "FACTER_#{key}='#{value}'"
24
+ end
25
+ end
26
+
27
+ facter = "#{facts.join(" ")} "
28
+ end
29
+ if env[:vm].config.vm.guest == :windows
30
+ command = "cd #{manifests_guest_path}; if($?) \{ #{facter} puppet apply #{options} \}"
31
+ else
32
+ command = "cd #{manifests_guest_path} && #{facter}puppet apply #{options}"
33
+ end
34
+
35
+ env[:ui].info I18n.t("vagrant.provisioners.puppet.running_puppet",
36
+ :manifest => @manifest_file)
37
+
38
+ env[:vm].channel.sudo(command) do |type, data|
39
+ env[:ui].info(data.chomp, :prefix => false)
40
+ end
41
+ end
42
+ def verify_binary(binary)
43
+ if env[:vm].config.vm.guest == :windows
44
+ command = "command #{binary}"
45
+ else
46
+ command = "which #{binary}"
47
+ end
48
+ env[:vm].channel.sudo(command,
49
+ :error_class => PuppetError,
50
+ :error_key => :not_detected,
51
+ :binary => binary)
52
+ end
53
+ def verify_shared_folders(folders)
54
+ folders.each do |folder|
55
+ @logger.debug("Checking for shared folder: #{folder}")
56
+
57
+
58
+ if env[:vm].config.vm.guest == :windows
59
+ if !env[:vm].channel.test("if(-not (test-path #{folder})) \{exit 1\} ")
60
+ raise PuppetError, :missing_shared_folders
61
+ end
62
+ else
63
+ if !env[:vm].channel.test("test -d #{folder}")
64
+ raise PuppetError, :missing_shared_folders
65
+ end
66
+ end
67
+
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,35 @@
1
+ require 'tempfile'
2
+
3
+ module Vagrant
4
+ module Provisioners
5
+ class Winrm < Base
6
+ class Config < Vagrant::Config::Base
7
+ attr_accessor :inline
8
+
9
+ def validate(env, errors)
10
+ # Validate that the parameters are properly set
11
+ if !inline
12
+ errors.add("No inline set")
13
+ end
14
+ end
15
+ end
16
+
17
+ def self.config_class
18
+ Config
19
+ end
20
+
21
+ def provision!
22
+ env[:vm].channel.sudo(config.inline) do |type, data|
23
+ if [:stderr, :stdout].include?(type)
24
+ # Output the data with the proper color based on the stream.
25
+ color = type == :stdout ? :green : :red
26
+
27
+ # Note: Be sure to chomp the data to avoid the newlines that the
28
+ # Chef outputs.
29
+ env[:ui].info(data.chomp, :color => color, :prefix => false)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,23 @@
1
+ function which {
2
+ $command = [Array](Get-Command $args[0] -errorAction continue)
3
+ write-host $command[0].Definition
4
+ }
5
+
6
+ function test ([Switch] $d, [String] $path) {
7
+ Resolve-Path $path| Out-Null;
8
+ }
9
+
10
+ function chown {
11
+ exit 0
12
+ }
13
+
14
+ function mkdir ([Switch] $p, [String] $path)
15
+ {
16
+ if(Test-Path $path)
17
+ {
18
+ exit 0
19
+ } else {
20
+ New-Item $p -Type Directory -Force | Out-Null
21
+ }
22
+ }
23
+
@@ -0,0 +1,49 @@
1
+
2
+ function Test-ReparsePoint([string]$path) {
3
+ $file = Get-Item $path -Force -ea 0
4
+ return [bool]($file.Attributes -band [IO.FileAttributes]::ReparsePoint)
5
+ }
6
+
7
+
8
+ $MountPoint = [System.IO.Path]::GetFullPath("<%= options[:mount_point] %>")
9
+ $ShareName = "<%= options[:name] %>"
10
+
11
+ # https://github.com/BIAINC/vagrant-windows/issues/4
12
+ # Not sure why this works, but it does.
13
+
14
+ & net use $ShareName 2>&1 | Out-Null
15
+
16
+ Write-Debug "Attempting to mount $ShareName to $MountPoint"
17
+ if( (Test-Path "$MountPoint") -and (Test-ReparsePoint "$MountPoint") )
18
+ {
19
+ Write-Debug "Junction already exists, so I will delete it"
20
+ # Powershell refuses to delete junctions, oh well use cmd
21
+ cmd /c rd "$MountPoint"
22
+
23
+ if ( $LASTEXITCODE -ne 0 )
24
+ {
25
+ Write-Error "Failed to delete symbolic link at $MountPoint"
26
+ exit 1
27
+ }
28
+
29
+ }
30
+ elseif(Test-Path $MountPoint)
31
+ {
32
+ Write-Debug "Mount point already exists and is not a symbolic link"
33
+ exit 1
34
+ }
35
+
36
+ $BaseDirectory = [System.IO.Path]::GetDirectoryName($MountPoint)
37
+
38
+ if (-not (Test-Path $BaseDirectory))
39
+ {
40
+ Write-Debug "Creating parent directory for mount point $BaseDirectory"
41
+ New-Item $BaseDirectory -Type Directory -Force | Out-Null
42
+ }
43
+
44
+ cmd /c mklink /D "$MountPoint" "\\vboxsrv\$ShareName" | out-null
45
+
46
+ if ( $LASTEXITCODE -ne 0 )
47
+ {
48
+ exit 1
49
+ }
@@ -0,0 +1,3 @@
1
+ module VagrantWindows
2
+ VERSION = "0.1.4"
3
+ end
@@ -0,0 +1,82 @@
1
+ require 'log4r'
2
+ #require 'em-winrm'
3
+
4
+ module Vagrant
5
+ # Manages WINRM access to a specific environment. Allows an environment to
6
+ # run commands, upload files, and check if a host is up.
7
+ class WinRM
8
+ include Util::SafeExec
9
+
10
+ def initialize(vm)
11
+ @vm = vm
12
+ @logger = Log4r::Logger.new("vagrant::winrm")
13
+ end
14
+
15
+ # Returns a hash of information necessary for accessing this
16
+ # virtual machine via WINRM.
17
+ #
18
+ # @return [Hash]
19
+ def info
20
+ results = {
21
+ :host => @vm.config.winrm.host,
22
+ :port => @vm.config.winrm.port || @vm.driver.ssh_port(@vm.config.winrm.guest_port),
23
+ :username => @vm.config.winrm.username
24
+ }
25
+
26
+ # This can happen if no port is set and for some reason Vagrant
27
+ # can't detect an SSH port.
28
+ raise Errors::WinRMPortNotDetected if !results[:port]
29
+
30
+ # Return the results
31
+ return results
32
+ end
33
+
34
+ # Checks if this environment's machine is up (i.e. responding to WINRM).
35
+ #
36
+ # @return [Boolean]
37
+ def up?
38
+ # We have to determine the port outside of the block since it uses
39
+ # API calls which can only be used from the main thread in JRuby on
40
+ # Windows
41
+ ssh_port = port
42
+
43
+ require 'timeout'
44
+ Timeout.timeout(@env.config.ssh.timeout) do
45
+ execute 'hostname'
46
+ end
47
+
48
+ true
49
+ rescue Timeout::Error, Errno::ECONNREFUSED
50
+ return false
51
+ end
52
+
53
+ # Returns the port which is either given in the options hash or taken from
54
+ # the config by finding it in the forwarded ports hash based on the
55
+ # `config.ssh.forwarded_port_key`.
56
+ def port(opts={})
57
+ # Check if port was specified in options hash
58
+ return opts[:port] if opts[:port]
59
+
60
+ # Check if a port was specified in the config
61
+ return @env.config.winrm.port if @env.config.winrm.port
62
+
63
+ # Check if we have an SSH forwarded port
64
+ pnum_by_name = nil
65
+ pnum_by_destination = nil
66
+ @logger.info("Looking for winrm port: #{opts}")
67
+ @logger.info("Looking for winrm port: #{env.config.winrm.inspect}")
68
+
69
+ env.vm.vm.network_adapters.each do |na|
70
+ # Look for the port number by destination...
71
+ pnum_by_destination = na.nat_driver.forwarded_ports.detect do |fp|
72
+ fp.guestport == env.config.winrm.guest_port
73
+ end
74
+ end
75
+
76
+ return pnum_by_destination.hostport if pnum_by_destination
77
+
78
+ # This should NEVER happen.
79
+ raise Errors::WinRMPortNotDetected
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,24 @@
1
+ #Add Windows Guest Defintion
2
+ require 'vagrant-windows/guest/windows'
3
+
4
+ #Add Configuration Items
5
+ require 'vagrant-windows/config/windows'
6
+ require 'vagrant-windows/config/winrm'
7
+
8
+ # Add WinRM Communication Channel
9
+ require 'vagrant-windows/communication/winrm'
10
+
11
+ # Add Provisioner
12
+ require 'vagrant-windows/provisioners/puppet'
13
+
14
+ #Monkey Patch the VM object to support multiple channels
15
+ require 'vagrant-windows/monkey_patches/vm'
16
+
17
+ #Monkey Patch the driver to support returning a mapping of mac addresses to nics
18
+ require 'vagrant-windows/monkey_patches/driver'
19
+
20
+ require 'vagrant-windows/winrm'
21
+
22
+ #Errors are good
23
+ require 'vagrant-windows/errors'
24
+
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/vagrant-windows/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Paul Morton"]
6
+ gem.email = ["pmorton@biaprotect.com"]
7
+ gem.description = %q{Windows Guest Support for Vagrant}
8
+ gem.summary = %q{A small gem that adds windows guest support to vagrant, uses WinRM as the Communication Channel}
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "realityforge-vagrant-windows"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = VagrantWindows::VERSION
17
+
18
+ gem.add_runtime_dependency "winrm", "~> 1.1.1"
19
+ gem.add_runtime_dependency 'vagrant', "~> 1.0"
20
+ gem.add_runtime_dependency 'highline'
21
+ end
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: realityforge-vagrant-windows
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.4
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Paul Morton
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-04-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: winrm
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 1.1.1
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 1.1.1
30
+ - !ruby/object:Gem::Dependency
31
+ name: vagrant
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '1.0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '1.0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: highline
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: Windows Guest Support for Vagrant
63
+ email:
64
+ - pmorton@biaprotect.com
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - .gitignore
70
+ - .ruby-version
71
+ - Gemfile
72
+ - README.md
73
+ - Rakefile
74
+ - lib/vagrant-windows/communication/winrm.rb
75
+ - lib/vagrant-windows/config/windows.rb
76
+ - lib/vagrant-windows/config/winrm.rb
77
+ - lib/vagrant-windows/errors.rb
78
+ - lib/vagrant-windows/guest/windows.rb
79
+ - lib/vagrant-windows/monkey_patches/driver.rb
80
+ - lib/vagrant-windows/monkey_patches/vm.rb
81
+ - lib/vagrant-windows/provisioners/puppet.rb
82
+ - lib/vagrant-windows/provisioners/winrm.rb
83
+ - lib/vagrant-windows/scripts/command_alias.ps1
84
+ - lib/vagrant-windows/scripts/mount_volume.ps1.erb
85
+ - lib/vagrant-windows/version.rb
86
+ - lib/vagrant-windows/winrm.rb
87
+ - lib/vagrant_init.rb
88
+ - vagrant-windows.gemspec
89
+ homepage: ''
90
+ licenses: []
91
+ post_install_message:
92
+ rdoc_options: []
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ! '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ! '>='
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 1.8.23
110
+ signing_key:
111
+ specification_version: 3
112
+ summary: A small gem that adds windows guest support to vagrant, uses WinRM as the
113
+ Communication Channel
114
+ test_files: []
115
+ has_rdoc: