vagrant-parallels 1.1.0 → 1.2.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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.