vagrant-parallels 1.1.0 → 1.2.0.rc1

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +61 -0
  3. data/README.md +2 -57
  4. data/lib/vagrant-parallels/action/clear_forwarded_ports.rb +25 -0
  5. data/lib/vagrant-parallels/action/customize.rb +2 -2
  6. data/lib/vagrant-parallels/action/export.rb +1 -1
  7. data/lib/vagrant-parallels/action/forward_ports.rb +78 -0
  8. data/lib/vagrant-parallels/action/handle_guest_tools.rb +1 -1
  9. data/lib/vagrant-parallels/action/import.rb +1 -1
  10. data/lib/vagrant-parallels/action/network.rb +47 -47
  11. data/lib/vagrant-parallels/action/prepare_forwarded_port_collision_params.rb +41 -0
  12. data/lib/vagrant-parallels/action/prepare_nfs_settings.rb +1 -1
  13. data/lib/vagrant-parallels/action/prepare_nfs_valid_ids.rb +1 -1
  14. data/lib/vagrant-parallels/action/sane_defaults.rb +55 -0
  15. data/lib/vagrant-parallels/action/set_name.rb +1 -1
  16. data/lib/vagrant-parallels/action/setup_package_files.rb +0 -1
  17. data/lib/vagrant-parallels/action.rb +16 -7
  18. data/lib/vagrant-parallels/cap/forwarded_ports.rb +22 -0
  19. data/lib/vagrant-parallels/driver/base.rb +8 -16
  20. data/lib/vagrant-parallels/driver/meta.rb +7 -7
  21. data/lib/vagrant-parallels/driver/pd_10.rb +279 -0
  22. data/lib/vagrant-parallels/driver/pd_8.rb +23 -15
  23. data/lib/vagrant-parallels/driver/pd_9.rb +1 -1
  24. data/lib/vagrant-parallels/guest_cap/linux/mount_parallels_shared_folder.rb +78 -22
  25. data/lib/vagrant-parallels/model/forwarded_port.rb +52 -0
  26. data/lib/vagrant-parallels/plugin.rb +14 -0
  27. data/lib/vagrant-parallels/provider.rb +12 -3
  28. data/lib/vagrant-parallels/synced_folder.rb +6 -1
  29. data/lib/vagrant-parallels/util/compile_forwarded_ports.rb +35 -0
  30. data/lib/vagrant-parallels/version.rb +1 -1
  31. data/locales/en.yml +3 -0
  32. data/test/unit/driver/pd_10_test.rb +228 -0
  33. data/test/unit/driver/pd_8_test.rb +27 -7
  34. data/test/unit/driver/pd_9_test.rb +28 -7
  35. data/test/unit/support/shared/parallels_context.rb +5 -4
  36. data/test/unit/support/shared/pd_driver_examples.rb +16 -37
  37. metadata +35 -27
  38. data/lib/vagrant-parallels/action/is_driver_version.rb +0 -28
  39. data/lib/vagrant-parallels/action/set_power_consumption.rb +0 -34
@@ -2,42 +2,98 @@ module VagrantPlugins
2
2
  module Parallels
3
3
  module GuestLinuxCap
4
4
  class MountParallelsSharedFolder
5
-
6
5
  def self.mount_parallels_shared_folder(machine, name, guestpath, options)
7
- # Expand the guest path so we can handle things like "~/vagrant"
8
6
  expanded_guest_path = machine.guest.capability(
9
7
  :shell_expand_guest_path, guestpath)
10
8
 
11
- machine.communicate.tap do |comm|
12
- # clear prior symlink
13
- if comm.test("test -L \"#{expanded_guest_path}\"", :sudo => true)
14
- comm.sudo("rm \"#{expanded_guest_path}\"")
15
- end
9
+ mount_commands = []
16
10
 
17
- # clear prior directory if exists
18
- if comm.test("test -d \"#{expanded_guest_path}\"", :sudo => true)
19
- comm.sudo("rm -Rf \"#{expanded_guest_path}\"")
20
- end
11
+ if options[:owner].is_a? Integer
12
+ mount_uid = options[:owner]
13
+ else
14
+ mount_uid = "`id -u #{options[:owner]}`"
15
+ end
16
+
17
+ if options[:group].is_a? Integer
18
+ mount_gid = options[:group]
19
+ mount_gid_old = options[:group]
20
+ else
21
+ mount_gid = "`getent group #{options[:group]} | cut -d: -f3`"
22
+ mount_gid_old = "`id -g #{options[:group]}`"
23
+ end
24
+
25
+ # First mount command uses getent to get the group
26
+ mount_options = "-o uid=#{mount_uid},gid=#{mount_gid}"
27
+ mount_options += ",#{options[:mount_options].join(",")}" if options[:mount_options]
28
+ mount_commands << "mount -t prl_fs #{mount_options} #{name} #{expanded_guest_path}"
29
+
30
+ # Second mount command uses the old style `id -g`
31
+ mount_options = "-o uid=#{mount_uid},gid=#{mount_gid_old}"
32
+ mount_options += ",#{options[:mount_options].join(",")}" if options[:mount_options]
33
+ mount_commands << "mount -t prl_fs #{mount_options} #{name} #{expanded_guest_path}"
34
+
35
+ # Clear prior symlink if exists
36
+ if machine.communicate.test("test -L #{expanded_guest_path}")
37
+ machine.communicate.sudo("rm #{expanded_guest_path}")
38
+ end
39
+
40
+ # Create the guest path if it doesn't exist
41
+ machine.communicate.sudo("mkdir -p #{expanded_guest_path}")
21
42
 
22
- # create intermediate directories if needed
23
- intermediate_dir = File.dirname(expanded_guest_path)
24
- if !comm.test("test -d \"#{intermediate_dir}\"", :sudo => true)
25
- comm.sudo("mkdir -p \"#{intermediate_dir}\"")
43
+ # Attempt to mount the folder. We retry here a few times because
44
+ # it can fail early on.
45
+ attempts = 0
46
+ while true
47
+ success = true
48
+
49
+ mount_commands.each do |command|
50
+ no_such_device = false
51
+ status = machine.communicate.sudo(command, error_check: false) do |type, data|
52
+ no_such_device = true if type == :stderr && data =~ /No such device/i
53
+ end
54
+
55
+ success = status == 0 && !no_such_device
56
+ break if success
26
57
  end
27
58
 
28
- # finally make the symlink
29
- comm.sudo("ln -s \"/media/psf/#{name}\" \"#{expanded_guest_path}\"")
59
+ break if success
30
60
 
31
- # Emit an upstart event if we can
32
- if comm.test("test -x /sbin/initctl")
33
- comm.sudo(
34
- "/sbin/initctl emit --no-wait vagrant-mounted MOUNTPOINT=#{expanded_guest_path}")
61
+ attempts += 1
62
+ if attempts > 10
63
+ raise Vagrant::Errors::LinuxMountFailed,
64
+ command: mount_commands.join("\n")
35
65
  end
66
+
67
+ sleep 2
68
+ end
69
+
70
+ # Emit an upstart event if we can
71
+ if machine.communicate.test("test -x /sbin/initctl")
72
+ machine.communicate.sudo(
73
+ "/sbin/initctl emit --no-wait vagrant-mounted MOUNTPOINT=#{expanded_guest_path}")
36
74
  end
37
75
  end
38
76
 
39
77
  def self.unmount_parallels_shared_folder(machine, guestpath, options)
40
- machine.communicate.sudo("rm #{guestpath}", error_check: false)
78
+ result = machine.communicate.sudo(
79
+ "umount #{guestpath}", error_check: false)
80
+ if result == 0
81
+ machine.communicate.sudo("rmdir #{guestpath}", error_check: false)
82
+ end
83
+ end
84
+
85
+ def self.prepare_psf_services(machine)
86
+ # Parallels Tools for Linux includes native auto-mount script,
87
+ # which causes loosing some of Vagrant-relative shared folders.
88
+ # So, we should to disable this behavior. [GH-102]
89
+
90
+ auto_mount_script = '/usr/bin/prlfsmountd'
91
+ if machine.communicate.test("test -f #{auto_mount_script}")
92
+ machine.communicate.sudo(
93
+ "echo -e '#!/bin/sh\n'" +
94
+ '# Shared folders auto-mount is disabled by Vagrant ' +
95
+ "> #{auto_mount_script}")
96
+ end
41
97
  end
42
98
  end
43
99
  end
@@ -0,0 +1,52 @@
1
+ module VagrantPlugins
2
+ module Parallels
3
+ module Model
4
+ # Represents a single forwarded port for Parallels Desktop. This has
5
+ # various helpers and defaults for a forwarded port.
6
+ class ForwardedPort
7
+ # If true, the forwarded port should be auto-corrected.
8
+ #
9
+ # @return [Boolean]
10
+ attr_reader :auto_correct
11
+
12
+ # The unique ID for the forwarded port.
13
+ #
14
+ # @return [String]
15
+ attr_reader :id
16
+
17
+ # The protocol to forward.
18
+ #
19
+ # @return [String]
20
+ attr_reader :protocol
21
+
22
+ # The port on the guest to be exposed on the host.
23
+ #
24
+ # @return [Integer]
25
+ attr_reader :guest_port
26
+
27
+ # The port on the host used to access the port on the guest.
28
+ #
29
+ # @return [Integer]
30
+ attr_reader :host_port
31
+
32
+ def initialize(id, host_port, guest_port, options)
33
+ @id = id
34
+ @guest_port = guest_port
35
+ @host_port = host_port
36
+
37
+ options ||= {}
38
+ @auto_correct = false
39
+ @auto_correct = options[:auto_correct] if options.has_key?(:auto_correct)
40
+ @protocol = options[:protocol] || "tcp"
41
+ end
42
+
43
+ # This corrects the host port and changes it to the given new port.
44
+ #
45
+ # @param [Integer] new_port The new port
46
+ def correct_host_port(new_port)
47
+ @host_port = new_port
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -50,6 +50,11 @@ module VagrantPlugins
50
50
  GuestLinuxCap::MountParallelsSharedFolder
51
51
  end
52
52
 
53
+ guest_capability(:linux, :prepare_psf_services) do
54
+ require_relative "guest_cap/linux/mount_parallels_shared_folder"
55
+ GuestLinuxCap::MountParallelsSharedFolder
56
+ end
57
+
53
58
  guest_capability(:linux, :install_parallels_tools) do
54
59
  require_relative "guest_cap/linux/install_parallels_tools"
55
60
  GuestLinuxCap::InstallParallelsTools
@@ -85,6 +90,15 @@ module VagrantPlugins
85
90
  autoload :Meta, File.expand_path("../driver/meta", __FILE__)
86
91
  autoload :PD_8, File.expand_path("../driver/pd_8", __FILE__)
87
92
  autoload :PD_9, File.expand_path("../driver/pd_9", __FILE__)
93
+ autoload :PD_10, File.expand_path("../driver/pd_10", __FILE__)
94
+ end
95
+
96
+ module Model
97
+ autoload :ForwardedPort, File.expand_path("../model/forwarded_port", __FILE__)
98
+ end
99
+
100
+ module Util
101
+ autoload :CompileForwardedPorts, File.expand_path("../util/compile_forwarded_ports", __FILE__)
88
102
  end
89
103
  end
90
104
  end
@@ -64,7 +64,7 @@ module VagrantPlugins
64
64
  # If the VM is not running that we can't possibly SSH into it
65
65
  return nil if state.id != :running
66
66
 
67
- detected_ip = @driver.read_guest_ip
67
+ detected_ip = @driver.ssh_ip
68
68
 
69
69
  # If ip couldn't be detected then we cannot possibly SSH into it,
70
70
  # and should return nil too.
@@ -72,8 +72,8 @@ module VagrantPlugins
72
72
 
73
73
  # Return ip from running machine, use ip from config if available
74
74
  return {
75
- :host => detected_ip,
76
- :port => @driver.ssh_port(@machine.config.ssh.guest_port)
75
+ host: detected_ip,
76
+ port: @driver.ssh_port(@machine.config.ssh.guest_port)
77
77
  }
78
78
  end
79
79
 
@@ -101,6 +101,15 @@ module VagrantPlugins
101
101
  Vagrant::MachineState.new(state_id, short, long)
102
102
  end
103
103
 
104
+ # Determines if the installed Parallels Desktop version is
105
+ # satisfied by the given constraint or group of constraints.
106
+ #
107
+ # @return [Boolean]
108
+ def pd_version_satisfies?(*constraints)
109
+ pd_version = Gem::Version.new(@driver.version)
110
+ Gem::Requirement.new(*constraints).satisfied_by?(pd_version)
111
+ end
112
+
104
113
  # Returns a human-friendly string version of this provider which
105
114
  # includes the machine's ID that this provider represents, if it
106
115
  # has one.
@@ -18,7 +18,6 @@ module VagrantPlugins
18
18
  hostpath = Vagrant::Util::Platform.cygwin_windows_path(hostpath)
19
19
  end
20
20
 
21
-
22
21
  defs << {
23
22
  name: os_friendly_id(id),
24
23
  hostpath: hostpath.to_s,
@@ -42,6 +41,12 @@ module VagrantPlugins
42
41
 
43
42
  shf_config = driver(machine).read_shared_folders
44
43
 
44
+ # Parallels Shared Folder services can override Vagrant synced folder
45
+ # configuration. These services should be pre-configured.
46
+ if machine.guest.capability?(:prepare_psf_services)
47
+ machine.guest.capability(:prepare_psf_services)
48
+ end
49
+
45
50
  # Go through each folder and mount
46
51
  machine.ui.output(I18n.t("vagrant.actions.vm.share_folders.mounting"))
47
52
  folders.each do |_ , data|
@@ -0,0 +1,35 @@
1
+ require 'vagrant/util/scoped_hash_override'
2
+
3
+ module VagrantPlugins
4
+ module Parallels
5
+ module Util
6
+ module CompileForwardedPorts
7
+ include Vagrant::Util::ScopedHashOverride
8
+
9
+ # This method compiles the forwarded ports into {ForwardedPort}
10
+ # models.
11
+ def compile_forwarded_ports(config)
12
+ mappings = {}
13
+
14
+ config.vm.networks.each do |type, options|
15
+ if type == :forwarded_port
16
+ guest_port = options[:guest]
17
+ host_port = options[:host]
18
+ protocol = options[:protocol] || "tcp"
19
+ options = scoped_hash_override(options, :parallels)
20
+ id = options[:id]
21
+
22
+ # If the forwarded port was marked as disabled, ignore.
23
+ next if options[:disabled]
24
+
25
+ mappings[host_port.to_s + protocol.to_s] =
26
+ Model::ForwardedPort.new(id, host_port, guest_port, options)
27
+ end
28
+ end
29
+
30
+ mappings.values
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,5 +1,5 @@
1
1
  module VagrantPlugins
2
2
  module Parallels
3
- VERSION = "1.1.0"
3
+ VERSION = "1.2.0.rc1"
4
4
  end
5
5
  end
data/locales/en.yml CHANGED
@@ -126,3 +126,6 @@ en:
126
126
  reload your VM.
127
127
  export:
128
128
  compacting: Compacting exported HDDs...
129
+ forward_ports:
130
+ forwarding_entry: |-
131
+ %{guest_port} => %{host_port}
@@ -0,0 +1,228 @@
1
+ require_relative "../base"
2
+
3
+ describe VagrantPlugins::Parallels::Driver::PD_10 do
4
+ include_context "parallels"
5
+ let(:parallels_version) { "10" }
6
+
7
+ let(:vm_name) {'VM_Name'}
8
+
9
+ let(:tpl_uuid) {'1234-some-template-uuid-5678'}
10
+ let(:tpl_name) {'Some_Template_Name'}
11
+
12
+ let(:tools_state) {'installed'}
13
+ let(:tools_version) {'10.0.23062.123456'}
14
+
15
+ let(:hostonly_iface) {'vnic10'}
16
+
17
+ let(:vnic_options) do {
18
+ name: 'vagrant_vnic6',
19
+ adapter_ip: '11.11.11.11',
20
+ netmask: '255.255.252.0',
21
+ dhcp: {
22
+ ip: '11.11.11.11',
23
+ lower: '11.11.8.1',
24
+ upper: '11.11.11.254'
25
+ }
26
+ } end
27
+
28
+ subject { VagrantPlugins::Parallels::Driver::Meta.new(uuid) }
29
+
30
+ it_behaves_like "parallels desktop driver"
31
+
32
+ before do
33
+ # Returns short info about all registered VMs
34
+ # `prlctl list --all --json`
35
+ subprocess.stub(:execute).
36
+ with("prlctl", "list", "--all", "--json", kind_of(Hash)) do
37
+ out = <<-eos
38
+ [
39
+ {
40
+ "uuid": "#{uuid}",
41
+ "status": "stopped",
42
+ "name": "#{vm_name}"
43
+ }
44
+ ]
45
+ eos
46
+ subprocess_result(stdout: out)
47
+ end
48
+
49
+ # Returns short info about all registered templates
50
+ # `prlctl list --all --json --template`
51
+ subprocess.stub(:execute).
52
+ with("prlctl", "list", "--all", "--json", "--template", kind_of(Hash)) do
53
+ out = <<-eos
54
+ [
55
+ {
56
+ "uuid": "1234-some-template-uuid-5678",
57
+ "name": "Some_Template_Name"
58
+ }
59
+ ]
60
+ eos
61
+ subprocess_result(stdout: out)
62
+ end
63
+
64
+
65
+ # Returns detailed info about specified VM or all registered VMs
66
+ # `prlctl list <vm_uuid> --info --json`
67
+ # `prlctl list --all --info --json`
68
+ subprocess.stub(:execute).
69
+ with("prlctl", "list", kind_of(String), "--info", "--json",
70
+ kind_of(Hash)) do
71
+ out = <<-eos
72
+ [
73
+ {
74
+ "ID": "#{uuid}",
75
+ "Name": "#{vm_name}",
76
+ "State": "stopped",
77
+ "Home": "/path/to/#{vm_name}.pvm/",
78
+ "GuestTools": {
79
+ "state": "#{tools_state}",
80
+ "version": "#{tools_version}"
81
+ },
82
+ "Hardware": {
83
+ "cpu": {
84
+ "cpus": 1
85
+ },
86
+ "memory": {
87
+ "size": "512Mb"
88
+ },
89
+ "hdd0": {
90
+ "enabled": true,
91
+ "image": "/path/to/disk1.hdd"
92
+ },
93
+ "net0": {
94
+ "enabled": true,
95
+ "type": "shared",
96
+ "mac": "001C42B4B074",
97
+ "card": "e1000",
98
+ "dhcp": "yes"
99
+ },
100
+ "net1": {
101
+ "enabled": true,
102
+ "type": "bridged",
103
+ "iface": "vnic2",
104
+ "mac": "001C42EC0068",
105
+ "card": "e1000",
106
+ "ips": "33.33.33.5/255.255.255.0 "
107
+ }
108
+ },
109
+ "Host Shared Folders": {
110
+ "enabled": true,
111
+ "shared_folder_1": {
112
+ "enabled": true,
113
+ "path": "/path/to/shared/folder/1"
114
+ },
115
+ "shared_folder_2": {
116
+ "enabled": true,
117
+ "path": "/path/to/shared/folder/2"
118
+ }
119
+ }
120
+ }
121
+ ]
122
+ eos
123
+ subprocess_result(stdout: out)
124
+ end
125
+
126
+ # Returns detailed info about specified template or all registered templates
127
+ # `prlctl list <tpl_uuid> --info --json --template`
128
+ # `prlctl list --all --info --json --template`
129
+ subprocess.stub(:execute).
130
+ with("prlctl", "list", kind_of(String), "--info", "--json", "--template",
131
+ kind_of(Hash)) do
132
+ out = <<-eos
133
+ [
134
+ {
135
+ "ID": "#{tpl_uuid}",
136
+ "Name": "#{tpl_name}",
137
+ "State": "stopped",
138
+ "Home": "/path/to/#{tpl_name}.pvm/",
139
+ "GuestTools": {
140
+ "state": "#{tools_state}",
141
+ "version": "#{tools_version}"
142
+ },
143
+ "Hardware": {
144
+ "cpu": {
145
+ "cpus": 1
146
+ },
147
+ "memory": {
148
+ "size": "512Mb"
149
+ },
150
+ "hdd0": {
151
+ "enabled": true,
152
+ "image": "/path/to/harddisk.hdd"
153
+ },
154
+ "net0": {
155
+ "enabled": true,
156
+ "type": "shared",
157
+ "mac": "001C42F6E500",
158
+ "card": "e1000",
159
+ "dhcp": "yes"
160
+ },
161
+ "net1": {
162
+ "enabled": true,
163
+ "type": "bridged",
164
+ "iface": "vnic4",
165
+ "mac": "001C42AB0071",
166
+ "card": "e1000",
167
+ "ips": "33.33.33.10/255.255.255.0 "
168
+ }
169
+ }
170
+ }
171
+ ]
172
+ eos
173
+ subprocess_result(stdout: out)
174
+ end
175
+
176
+ # Returns detailed info about virtual network interface
177
+ # `prlsrvctl net info <net_name>, '--json', retryable: true)
178
+ subprocess.stub(:execute).
179
+ with("prlsrvctl", "net", "info", kind_of(String), "--json",
180
+ kind_of(Hash)) do
181
+ out = <<-eos
182
+ {
183
+ "Network ID": "#{vnic_options[:name]}",
184
+ "Type": "host-only",
185
+ "Bound To": "#{hostonly_iface}",
186
+ "Parallels adapter": {
187
+ "IP address": "#{vnic_options[:adapter_ip]}",
188
+ "Subnet mask": "#{vnic_options[:netmask]}"
189
+ },
190
+ "DHCPv4 server": {
191
+ "Server address": "#{vnic_options[:dhcp][:ip] || "10.37.132.1"}",
192
+ "IP scope start address": "#{vnic_options[:dhcp][:lower] || "10.37.132.1"}",
193
+ "IP scope end address": "#{vnic_options[:dhcp][:upper] || "10.37.132.254"}"
194
+ }
195
+ }
196
+ eos
197
+ subprocess_result(stdout: out)
198
+ end
199
+
200
+ end
201
+
202
+ describe "set_power_consumption_mode" do
203
+ it "turns 'longer-battery-life' on" do
204
+ subprocess.should_receive(:execute).
205
+ with("prlctl", "set", uuid, "--longer-battery-life", "on",
206
+ an_instance_of(Hash)).
207
+ and_return(subprocess_result(exit_code: 0))
208
+
209
+ subject.set_power_consumption_mode(true)
210
+ end
211
+
212
+ it "turns 'longer-battery-life' off" do
213
+ subprocess.should_receive(:execute).
214
+ with("prlctl", "set", uuid, "--longer-battery-life", "off",
215
+ an_instance_of(Hash)).
216
+ and_return(subprocess_result(exit_code: 0))
217
+
218
+ subject.set_power_consumption_mode(false)
219
+ end
220
+ end
221
+
222
+ describe "ssh_ip" do
223
+ it "returns 127.0.0.1" do
224
+ subject.ssh_ip.should == "127.0.0.1"
225
+ end
226
+ end
227
+
228
+ end
@@ -15,13 +15,13 @@ describe VagrantPlugins::Parallels::Driver::PD_8 do
15
15
  let(:hostonly_iface) {'vnic10'}
16
16
 
17
17
  let(:vnic_options) do {
18
- :name => 'vagrant_vnic6',
19
- :adapter_ip => '11.11.11.11',
20
- :netmask => '255.255.252.0',
21
- :dhcp => {
22
- :ip => '11.11.11.11',
23
- :lower => '11.11.8.1',
24
- :upper => '11.11.11.254'
18
+ name: 'vagrant_vnic6',
19
+ adapter_ip: '11.11.11.11',
20
+ netmask: '255.255.252.0',
21
+ dhcp: {
22
+ ip: '11.11.11.11',
23
+ lower: '11.11.8.1',
24
+ upper: '11.11.11.254'
25
25
  }
26
26
  } end
27
27
 
@@ -198,4 +198,24 @@ INFO[
198
198
  end
199
199
 
200
200
  end
201
+
202
+ describe "ssh_ip" do
203
+ let(:content) {'10.200.0.99="1394547632,1800,001c420000ff,01001c420000ff"'}
204
+
205
+ it "returns an IP address assigned to the specified MAC" do
206
+ driver.should_receive(:read_mac_address).and_return("001C420000FF")
207
+ File.should_receive(:open).with(an_instance_of(String)).
208
+ and_return(StringIO.new(content))
209
+
210
+ subject.ssh_ip.should == "10.200.0.99"
211
+ end
212
+
213
+ it "rises DhcpLeasesNotAccessible exception when file is not accessible" do
214
+ File.stub(:open).and_call_original
215
+ File.should_receive(:open).with(an_instance_of(String)).
216
+ and_raise(Errno::EACCES)
217
+ expect { subject.ssh_ip }.
218
+ to raise_error(VagrantPlugins::Parallels::Errors::DhcpLeasesNotAccessible)
219
+ end
220
+ end
201
221
  end
@@ -15,13 +15,13 @@ describe VagrantPlugins::Parallels::Driver::PD_9 do
15
15
  let(:hostonly_iface) {'vnic10'}
16
16
 
17
17
  let(:vnic_options) do {
18
- :name => 'vagrant_vnic6',
19
- :adapter_ip => '11.11.11.11',
20
- :netmask => '255.255.252.0',
21
- :dhcp => {
22
- :ip => '11.11.11.11',
23
- :lower => '11.11.8.1',
24
- :upper => '11.11.11.254'
18
+ name: 'vagrant_vnic6',
19
+ adapter_ip: '11.11.11.11',
20
+ netmask: '255.255.252.0',
21
+ dhcp: {
22
+ ip: '11.11.11.11',
23
+ lower: '11.11.8.1',
24
+ upper: '11.11.11.254'
25
25
  }
26
26
  } end
27
27
 
@@ -218,4 +218,25 @@ describe VagrantPlugins::Parallels::Driver::PD_9 do
218
218
  subject.set_power_consumption_mode(false)
219
219
  end
220
220
  end
221
+
222
+ describe "ssh_ip" do
223
+ let(:content) {'10.200.0.99="1394547632,1800,001c420000ff,01001c420000ff"'}
224
+
225
+ it "returns an IP address assigned to the specified MAC" do
226
+ driver.should_receive(:read_mac_address).and_return("001C420000FF")
227
+ File.should_receive(:open).with(an_instance_of(String)).
228
+ and_return(StringIO.new(content))
229
+
230
+ subject.ssh_ip.should == "10.200.0.99"
231
+ end
232
+
233
+ it "rises DhcpLeasesNotAccessible exception when file is not accessible" do
234
+ File.stub(:open).and_call_original
235
+ File.should_receive(:open).with(an_instance_of(String)).
236
+ and_raise(Errno::EACCES)
237
+ expect { subject.ssh_ip }.
238
+ to raise_error(VagrantPlugins::Parallels::Errors::DhcpLeasesNotAccessible)
239
+ end
240
+ end
241
+
221
242
  end
@@ -1,8 +1,9 @@
1
1
  shared_context "parallels" do
2
- let(:parallels_context) { true }
3
- let(:uuid) { "1234-here-is-uuid-5678" }
4
- let(:parallels_version) { "9" }
5
- let(:subprocess) { double("Vagrant::Util::Subprocess") }
2
+ let(:parallels_context) { true }
3
+ let(:uuid) { "1234-here-is-uuid-5678" }
4
+ let(:parallels_version) { "9" }
5
+ let(:subprocess) { double("Vagrant::Util::Subprocess") }
6
+ let(:driver) { subject.instance_variable_get("@driver") }
6
7
 
7
8
  # this is a helper that returns a duck type suitable from a system command
8
9
  # execution; allows setting exit_code, stdout, and stderr in stubs.