vagrant-parallels 1.6.2 → 1.6.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -0
  3. data/LICENSE.txt +1 -1
  4. data/lib/vagrant-parallels/action.rb +7 -0
  5. data/lib/vagrant-parallels/action/box_unregister.rb +3 -0
  6. data/lib/vagrant-parallels/action/check_shared_interface.rb +29 -0
  7. data/lib/vagrant-parallels/action/clear_forwarded_ports.rb +3 -2
  8. data/lib/vagrant-parallels/action/export.rb +69 -6
  9. data/lib/vagrant-parallels/action/forward_ports.rb +1 -1
  10. data/lib/vagrant-parallels/action/network.rb +8 -10
  11. data/lib/vagrant-parallels/action/sane_defaults.rb +2 -1
  12. data/lib/vagrant-parallels/cap.rb +0 -1
  13. data/lib/vagrant-parallels/config.rb +18 -8
  14. data/lib/vagrant-parallels/driver/base.rb +68 -24
  15. data/lib/vagrant-parallels/driver/meta.rb +3 -1
  16. data/lib/vagrant-parallels/driver/pd_10.rb +36 -39
  17. data/lib/vagrant-parallels/driver/pd_11.rb +4 -0
  18. data/lib/vagrant-parallels/driver/pd_8.rb +31 -27
  19. data/lib/vagrant-parallels/errors.rb +10 -2
  20. data/lib/vagrant-parallels/version.rb +1 -1
  21. data/locales/en.yml +25 -9
  22. metadata +4 -29
  23. data/.gitignore +0 -34
  24. data/.travis.yml +0 -10
  25. data/CONTRIBUTING.md +0 -80
  26. data/Gemfile +0 -14
  27. data/Rakefile +0 -21
  28. data/debug.log +0 -1237
  29. data/tasks/acceptance.rake +0 -28
  30. data/tasks/bundler.rake +0 -3
  31. data/tasks/test.rake +0 -8
  32. data/test/acceptance/base.rb +0 -2
  33. data/test/acceptance/provider/linked_clone_spec.rb +0 -30
  34. data/test/acceptance/provider/snapshot_spec.rb +0 -63
  35. data/test/acceptance/shared/context_parallels.rb +0 -2
  36. data/test/acceptance/skeletons/linked_clone/Vagrantfile +0 -7
  37. data/test/unit/base.rb +0 -24
  38. data/test/unit/cap_test.rb +0 -96
  39. data/test/unit/config_test.rb +0 -91
  40. data/test/unit/driver/pd_10_test.rb +0 -31
  41. data/test/unit/driver/pd_8_test.rb +0 -10
  42. data/test/unit/driver/pd_9_test.rb +0 -29
  43. data/test/unit/support/shared/parallels_context.rb +0 -230
  44. data/test/unit/support/shared/pd_driver_examples.rb +0 -339
  45. data/test/unit/synced_folder_test.rb +0 -49
  46. data/vagrant-parallels.gemspec +0 -59
  47. data/vagrant-spec.config.example.rb +0 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7d0df49aa2a8f022bfe2918179f34f185e991566
4
- data.tar.gz: 7e31ce9a5505febbd9d277dd60b50ebbf65cfd46
3
+ metadata.gz: 96a1ffdfb9901688a2af90776e4c7f86c1ea5d27
4
+ data.tar.gz: dedfe0e23fbcaf6b429f31f422bb96b32ad2c7da
5
5
  SHA512:
6
- metadata.gz: 2f1178440b0b9a8f81eefe23a6ba557dcc0f74de988716bb35b659746aa7524c84f8f26e497714b10362f2656bed6aedfea4c553d32e86bed1763d3d907252da
7
- data.tar.gz: 5ff89e1b90270540a21cf0baedab86b11eaac25951e39f96b9a11e4e97fb8a4905d0296009f589eb54de7ac14ad792db2333dcb2ed137a8c1f41a00f36599fd1
6
+ metadata.gz: 20bc34e6060d31b4af5656c360146104f90fad6d967797c2f6d674f50f5ab5da2c9505dd97cb6c9f919f79e9fe6309412e7a1582ffe8f5587b4c52a1c05e574c
7
+ data.tar.gz: 9ced0b39362f1f48a7bffb36f7b5477ddac77ef37ff475fc1dd836f066aefd5912a146e729962a7658ffe6222dd8dc0723b64993cd24a5bee73ef8e4095a3529
data/CHANGELOG.md CHANGED
@@ -1,3 +1,32 @@
1
+ ## 1.6.3 (July 11, 2016)
2
+ DEPRECATIONS:
3
+ - The following provider options was renamed:
4
+ - `regen_box_uuid` was renamed to `regen_src_uuid`
5
+ - `use_linked_clone` was renamed to `linked clone`
6
+
7
+ Old names are still supported, but will be removed in `vagrant-parallels` v1.7.0.
8
+ [[GH-260](https://github.com/Parallels/vagrant-parallels/pull/260)]
9
+
10
+ IMPROVEMENTS:
11
+ - Allow to package linked clones with `vagrant package`. External disk images
12
+ will be automatically copied, so the resulted box become a full-sized
13
+ standalone VM. [[GH-262](https://github.com/Parallels/vagrant-parallels/pull/262)]
14
+ - Handle the situation when host machine is not connected to Shared network.
15
+ With Parallels Desktop 11.2.1+ Vagrant will connect it automatically. With earlier
16
+ versions, the human-readable error message will be displayed.
17
+ [[GH-266](https://github.com/Parallels/vagrant-parallels/pull/266)]
18
+ - Disable home folder sharing by default (Parallels Desktop 11+).
19
+ [[GH-257](https://github.com/Parallels/vagrant-parallels/pull/257)]
20
+
21
+ BUG FIXES:
22
+ - action/box_unregister: Fix `#recover` method for layered environments.
23
+ [[GH-261](https://github.com/Parallels/vagrant-parallels/pull/261)]
24
+ - action/network: Fix an exception when option "Connect Mac to
25
+ this network" is disabled. [[GH-268](https://github.com/Parallels/vagrant-parallels/pull/268)]
26
+ - commands/snapshot: Add retries for snapshot commands to avoid `prlctl`
27
+ failures. [[GH-259](https://github.com/Parallels/vagrant-parallels/pull/259)]
28
+
29
+
1
30
  ## 1.6.2 (March 23, 2016)
2
31
  BUG FIXES:
3
32
  - Fix unsupported action error for `vagrant snapshot` commands [[GH-254](https://github.com/Parallels/vagrant-parallels/pull/254)]
data/LICENSE.txt CHANGED
@@ -1,5 +1,5 @@
1
1
  Copyright (c) 2013 Youssef Shahin
2
- Copyright (c) 2013-2015 Parallels IP Holdings GmbH.
2
+ Copyright (c) 2013-2016 Parallels IP Holdings GmbH.
3
3
 
4
4
  MIT License
5
5
 
@@ -11,6 +11,7 @@ module VagrantPlugins
11
11
  # a bootup (i.e. not saved).
12
12
  def self.action_boot
13
13
  Vagrant::Action::Builder.new.tap do |b|
14
+ b.use CheckSharedInterface
14
15
  b.use SetName
15
16
  b.use ClearForwardedPorts
16
17
  b.use Provision
@@ -74,6 +75,7 @@ module VagrantPlugins
74
75
  def self.action_halt
75
76
  Vagrant::Action::Builder.new.tap do |b|
76
77
  b.use ConfigValidate
78
+ b.use CheckSharedInterface
77
79
  b.use Call, IsState, :not_created do |env1, b1|
78
80
  if env1[:result]
79
81
  b1.use Message, I18n.t('vagrant.commands.common.vm_not_created')
@@ -122,6 +124,7 @@ module VagrantPlugins
122
124
  def self.action_provision
123
125
  Vagrant::Action::Builder.new.tap do |b|
124
126
  b.use ConfigValidate
127
+ b.use CheckSharedInterface
125
128
  b.use Call, IsState, :not_created do |env1, b1|
126
129
  if env1[:result]
127
130
  b1.use Message, I18n.t('vagrant.commands.common.vm_not_created')
@@ -163,6 +166,7 @@ module VagrantPlugins
163
166
  def self.action_resume
164
167
  Vagrant::Action::Builder.new.tap do |b|
165
168
  b.use ConfigValidate
169
+ b.use CheckSharedInterface
166
170
  b.use Call, IsState, :not_created do |env1, b1|
167
171
  if env1[:result]
168
172
  b1.use Message, I18n.t('vagrant.commands.common.vm_not_created')
@@ -227,6 +231,7 @@ module VagrantPlugins
227
231
  def self.action_ssh
228
232
  Vagrant::Action::Builder.new.tap do |b|
229
233
  b.use ConfigValidate
234
+ b.use CheckSharedInterface
230
235
  b.use Call, IsState, :not_created do |env1, b1|
231
236
  if env1[:result]
232
237
  b1.use Message, I18n.t('vagrant.commands.common.vm_not_created')
@@ -248,6 +253,7 @@ module VagrantPlugins
248
253
  def self.action_ssh_run
249
254
  Vagrant::Action::Builder.new.tap do |b|
250
255
  b.use ConfigValidate
256
+ b.use CheckSharedInterface
251
257
  b.use Call, IsState, :not_created do |env1, b1|
252
258
  if env1[:result]
253
259
  b1.use Message, I18n.t('vagrant.commands.common.vm_not_created')
@@ -389,6 +395,7 @@ module VagrantPlugins
389
395
  autoload :BoxUnregister, File.expand_path('../action/box_unregister', __FILE__)
390
396
  autoload :HandleGuestTools, File.expand_path('../action/handle_guest_tools', __FILE__)
391
397
  autoload :HandleForwardedPortCollisions, File.expand_path('../action/handle_forwarded_port_collisions.rb', __FILE__)
398
+ autoload :CheckSharedInterface, File.expand_path('../action/check_shared_interface', __FILE__)
392
399
  autoload :ClearNetworkInterfaces, File.expand_path('../action/clear_network_interfaces', __FILE__)
393
400
  autoload :ClearForwardedPorts, File.expand_path('../action/clear_forwarded_ports', __FILE__)
394
401
  autoload :Customize, File.expand_path('../action/customize', __FILE__)
@@ -33,6 +33,9 @@ module VagrantPlugins
33
33
  end
34
34
 
35
35
  def recover(env)
36
+ # If we don't have a box, nothing to do
37
+ return if !env[:machine].box
38
+
36
39
  unregister_box(env)
37
40
  end
38
41
 
@@ -0,0 +1,29 @@
1
+ module VagrantPlugins
2
+ module Parallels
3
+ module Action
4
+ class CheckSharedInterface
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ shared_iface = env[:machine].provider.driver.read_shared_interface
11
+
12
+ # Shared interface is connected. Just exit
13
+ return @app.call(env) if shared_iface[:status] == 'Up'
14
+
15
+ # Since PD 11.2.1 Vagrant can fix this automatically
16
+ if !env[:machine].provider.pd_version_satisfies?('>= 11.2.1')
17
+ raise Errors::SharedInterfaceDisconnected
18
+ end
19
+
20
+ env[:ui].info I18n.t('vagrant_parallels.actions.vm.check_shared_interface.connecting')
21
+ iface_name = env[:machine].provider.driver.read_shared_network_id
22
+ env[:machine].provider.driver.connect_network_interface(iface_name)
23
+
24
+ @app.call(env)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -12,9 +12,10 @@ module VagrantPlugins
12
12
  return @app.call(env)
13
13
  end
14
14
 
15
- if !env[:machine].provider.driver.read_forwarded_ports.empty?
15
+ ports = env[:machine].provider.driver.read_forwarded_ports
16
+ if !ports.empty?
16
17
  env[:ui].info I18n.t('vagrant.actions.vm.clear_forward_ports.deleting')
17
- env[:machine].provider.driver.clear_forwarded_ports
18
+ env[:machine].provider.driver.clear_forwarded_ports(ports)
18
19
  end
19
20
 
20
21
  @app.call(env)
@@ -12,8 +12,18 @@ module VagrantPlugins
12
12
  raise Vagrant::Errors::VMPowerOffToPackage
13
13
  end
14
14
 
15
+ # Clone source VM to the temporary copy
15
16
  clone(env)
17
+ @home_path = env[:machine].provider.driver.read_settings(env[:package_box_id]).fetch('Home')
18
+ @hdd_list = Dir.glob(File.join(@home_path, '*.hdd'))
19
+
20
+ # Convert to full-sized VM, copy all external and linked disks (if any)
21
+ convert_to_full(env)
22
+
23
+ # Compact all virtual disks
16
24
  compact(env)
25
+
26
+ # Preparations completed. Unregister before packaging
17
27
  unregister_vm(env)
18
28
 
19
29
  @app.call(env)
@@ -71,16 +81,69 @@ module VagrantPlugins
71
81
  env[:ui].clear_line
72
82
  end
73
83
 
84
+ def convert_to_full(env)
85
+ is_linked = false
86
+
87
+ @hdd_list.each do |hdd_dir|
88
+ disk_desc = File.join(hdd_dir, 'DiskDescriptor.xml')
89
+ xml = Nokogiri::XML(File.open disk_desc)
90
+
91
+ linked_images = xml.xpath('//Parallels_disk_image/StorageData/Storage/Image/File').select do |hds|
92
+ Pathname.new(hds).absolute?
93
+ end
94
+
95
+ # If this is a regular, not linked HDD, then skip it. Otherwise,
96
+ # remember this VM as a linked clone.
97
+ next if linked_images.empty?
98
+ is_linked = true
99
+
100
+
101
+ env[:ui].info I18n.t('vagrant_parallels.actions.vm.export.copying_linked_disks')
102
+ linked_images.each do |hds|
103
+ hds_path = hds.text
104
+
105
+ if !File.exist?(hds_path)
106
+ raise VagrantPlugins::Parallels::Errors::ExternalDiskNotFound,
107
+ path: hds_path
108
+ end
109
+
110
+ FileUtils.cp(hds_path, hdd_dir, preserve: true)
111
+
112
+ # Save relative hds path to the XML file
113
+ hds.content = File.basename(hds_path)
114
+ end
115
+
116
+ File.open(disk_desc, 'w') do |f|
117
+ f.write xml.to_xml
118
+ end
119
+ end
120
+
121
+ # Flush elements LinkedVmUuid, LinkedSnapshotUuid from "config.pvs"
122
+ if is_linked
123
+ @logger.debug 'Converting linked clone to the regular VM'
124
+ config_pvs = File.join(@home_path, 'config.pvs')
125
+
126
+ xml = Nokogiri::XML(File.open(config_pvs))
127
+ xml.xpath('//ParallelsVirtualMachine/Identification/LinkedVmUuid').first.content = ''
128
+ xml.xpath('//ParallelsVirtualMachine/Identification/LinkedSnapshotUuid').first.content = ''
129
+
130
+ File.open(config_pvs, 'w') do |f|
131
+ f.write xml.to_xml
132
+ end
133
+ end
134
+ end
135
+
74
136
  def compact(env)
75
137
  env[:ui].info I18n.t('vagrant_parallels.actions.vm.export.compacting')
76
- env[:machine].provider.driver.compact(env[:package_box_id]) do |progress|
138
+ @hdd_list.each do |hdd|
139
+ env[:machine].provider.driver.compact_hdd(hdd) do |progress|
140
+ env[:ui].clear_line
141
+ env[:ui].report_progress(progress, 100, false)
142
+ end
143
+ # Clear the line a final time so the next data can appear
144
+ # alone on the line.
77
145
  env[:ui].clear_line
78
- env[:ui].report_progress(progress, 100, false)
79
146
  end
80
-
81
- # Clear the line a final time so the next data can appear
82
- # alone on the line.
83
- env[:ui].clear_line
84
147
  end
85
148
 
86
149
  def unregister_vm(env)
@@ -45,7 +45,7 @@ module VagrantPlugins
45
45
 
46
46
  def forward_ports
47
47
  all_rules = @env[:machine].provider.driver.read_forwarded_ports(true)
48
- names_in_use = all_rules.collect { |r| r[:rule_name] }
48
+ names_in_use = all_rules.collect { |r| r[:name] }
49
49
  ports = []
50
50
 
51
51
  @env[:forwarded_ports].each do |fp|
@@ -444,20 +444,18 @@ module VagrantPlugins
444
444
 
445
445
  # This finds a matching host only network for the given configuration.
446
446
  def hostonly_find_matching_network(config)
447
- existing = @env[:machine].provider.driver.read_host_only_interfaces
447
+ this_netaddr = network_address(config[:ip], config[:netmask])
448
448
 
449
- if config[:name]
450
- # Search networks strongly by specified name
451
- matched_iface = existing.detect { |i| config[:name] == i[:name] }
452
- else
453
- # Name is not specified - search by network address
454
- this_netaddr = network_address(config[:ip], config[:netmask])
455
- matched_iface = existing.detect do |i|
456
- this_netaddr == network_address(i[:ip], i[:netmask])
449
+ @env[:machine].provider.driver.read_host_only_interfaces.each do |interface|
450
+ return interface if config[:name] && config[:name] == interface[:name]
451
+
452
+ if interface[:ip]
453
+ return interface if this_netaddr == \
454
+ network_address(interface[:ip], interface[:netmask])
457
455
  end
458
456
  end
459
457
 
460
- matched_iface || nil
458
+ nil
461
459
  end
462
460
  end
463
461
  end
@@ -61,7 +61,8 @@ module VagrantPlugins
61
61
  settings.merge!(
62
62
  startup_view: 'headless',
63
63
  time_sync: 'on',
64
- disable_timezone_sync: 'on'
64
+ disable_timezone_sync: 'on',
65
+ shf_host_defined: 'off'
65
66
  )
66
67
 
67
68
  settings
@@ -23,7 +23,6 @@ module VagrantPlugins
23
23
  #
24
24
  # @return [String] Host's IP address
25
25
  def self.host_address(machine)
26
-
27
26
  shared_iface = machine.provider.driver.read_shared_interface
28
27
  return shared_iface[:ip] if shared_iface
29
28
 
@@ -13,13 +13,13 @@ module VagrantPlugins
13
13
  attr_accessor :regen_src_uuid
14
14
  attr_accessor :update_guest_tools
15
15
 
16
+ # Deprecated options
17
+ attr_accessor :regen_box_uuid
18
+ attr_accessor :use_linked_clone
19
+
16
20
  # Compatibility with virtualbox provider's syntax
17
21
  alias :check_guest_additions= :check_guest_tools=
18
22
 
19
- # Compatibility with old names
20
- alias :regen_box_uuid= :regen_src_uuid=
21
- alias :use_linked_clone= :linked_clone=
22
-
23
23
  def initialize
24
24
  @check_guest_tools = UNSET_VALUE
25
25
  @customizations = []
@@ -34,6 +34,10 @@ module VagrantPlugins
34
34
  @update_guest_tools = UNSET_VALUE
35
35
 
36
36
  network_adapter(0, :shared)
37
+
38
+ # Deprecated options
39
+ @regen_box_uuid = UNSET_VALUE
40
+ @use_linked_clone = UNSET_VALUE
37
41
  end
38
42
 
39
43
  def customize(*command)
@@ -55,10 +59,6 @@ module VagrantPlugins
55
59
  customize('pre-boot', ['set', :id, '--cpus', count.to_i])
56
60
  end
57
61
 
58
- def regen_box_uuid=(value)
59
- @regen_src_uuid = value
60
- end
61
-
62
62
  def merge(other)
63
63
  super.tap do |result|
64
64
  c = customizations.dup
@@ -68,6 +68,16 @@ module VagrantPlugins
68
68
  end
69
69
 
70
70
  def finalize!
71
+ if @regen_box_uuid != UNSET_VALUE
72
+ puts "Parallels provider: Vagrantfile option 'regen_box_uuid' is deprecated and will be removed. Please, use 'regen_src_uuid' instead"
73
+ @regen_src_uuid = @regen_box_uuid if @regen_src_uuid == UNSET_VALUE
74
+ end
75
+
76
+ if @use_linked_clone != UNSET_VALUE
77
+ puts "Parallels provider: Vagrantfile option 'use_linked_clone' is deprecated and will be removed. Please, use 'linked_clone' instead"
78
+ @linked_clone = @use_linked_clone if @linked_clone == UNSET_VALUE
79
+ end
80
+
71
81
  if @check_guest_tools == UNSET_VALUE
72
82
  @check_guest_tools = true
73
83
  end
@@ -3,6 +3,7 @@ require 'log4r'
3
3
  require 'vagrant/util/busy'
4
4
  require 'vagrant/util/network_ip'
5
5
  require 'vagrant/util/platform'
6
+ require 'vagrant/util/retryable'
6
7
  require 'vagrant/util/subprocess'
7
8
  require 'vagrant/util/which'
8
9
 
@@ -39,8 +40,20 @@ module VagrantPlugins
39
40
  @logger.info("prlsrvctl path: #{@prlsrvctl_path}")
40
41
  end
41
42
 
42
- # Removes all port forwarding rules for the virtual machine.
43
- def clear_forwarded_ports
43
+ # Removes the specified port forwarding rules for the virtual machine.
44
+ #
45
+ # @param [Array<Symbol => String>] ports - List of ports.
46
+ # Each port should be described as a hash with the following keys:
47
+ #
48
+ # {
49
+ # name: 'example',
50
+ # protocol: 'tcp',
51
+ # guest: 'target-vm-uuid',
52
+ # hostport: '8080',
53
+ # guestport: '80'
54
+ # }
55
+ #
56
+ def clear_forwarded_ports(ports)
44
57
  raise NotImplementedError
45
58
  end
46
59
 
@@ -81,24 +94,28 @@ module VagrantPlugins
81
94
  read_vms[dst_name]
82
95
  end
83
96
 
84
- # Compacts all disk drives of virtual machine
85
- def compact(uuid)
86
- hw_info = read_settings(uuid).fetch('Hardware', {})
87
- used_drives = hw_info.select do |name, _|
88
- name.start_with? 'hdd'
89
- end
90
- used_drives.each_value do |drive_params|
91
- execute(@prldisktool_path, 'compact', '--hdd', drive_params['image']) do |_, data|
92
- lines = data.split('\r')
93
- # The progress of the compact will be in the last line. Do a greedy
94
- # regular expression to find what we're looking for.
95
- if lines.last =~ /.+?(\d{,3}) ?%/
96
- yield $1.to_i if block_given?
97
- end
97
+ # Compacts the specified virtual disk image
98
+ #
99
+ # @param [<String>] hdd_path Path to the target '*.hdd'
100
+ def compact_hdd(hdd_path)
101
+ execute(@prldisktool_path, 'compact', '--hdd', hdd_path) do |_, data|
102
+ lines = data.split('\r')
103
+ # The progress of the compact will be in the last line. Do a greedy
104
+ # regular expression to find what we're looking for.
105
+ if lines.last =~ /.+?(\d{,3}) ?%/
106
+ yield $1.to_i if block_given?
98
107
  end
99
108
  end
100
109
  end
101
110
 
111
+ # Connects the host machine to the specified virtual network interface
112
+ # Could be used for Parallels' Shared and Host-Only interfaces only.
113
+ #
114
+ # @param [<String>] name Network interface name. Example: 'Shared'
115
+ def connect_network_interface(name)
116
+ raise NotImplementedError
117
+ end
118
+
102
119
  # Creates a host only network with the given options.
103
120
  #
104
121
  # @param [<Symbol => String>] options Hostonly network options.
@@ -161,7 +178,11 @@ module VagrantPlugins
161
178
  # @param [String] uuid Name or UUID of the target VM
162
179
  # @param [String] snapshot_id Snapshot ID
163
180
  def delete_snapshot(uuid, snapshot_id)
164
- execute_prlctl('snapshot-delete', uuid, '--id', snapshot_id)
181
+ # Sometimes this command fails with 'Data synchronization is currently
182
+ # in progress'. Just wait and retry.
183
+ retryable(on: VagrantPlugins::Parallels::Errors::ExecutionError, tries: 2, sleep: 2) do
184
+ execute_prlctl('snapshot-delete', uuid, '--id', snapshot_id)
185
+ end
165
186
  end
166
187
 
167
188
  # Deletes any host only networks that aren't being used for anything.
@@ -292,6 +313,20 @@ module VagrantPlugins
292
313
  bridged_ifaces
293
314
  end
294
315
 
316
+ # Returns the list of port forwarding rules.
317
+ # Each rule will be represented as a hash with the following keys:
318
+ #
319
+ # {
320
+ # name: 'example',
321
+ # protocol: 'tcp',
322
+ # guest: 'target-vm-uuid',
323
+ # hostport: '8080',
324
+ # guestport: '80'
325
+ # }
326
+ #
327
+ # @param [Boolean] global If true, returns all the rules on the host.
328
+ # Otherwise only rules related to the context VM will be returned.
329
+ # @return [Array<Symbol => String>]
295
330
  def read_forwarded_ports(global=false)
296
331
  raise NotImplementedError
297
332
  end
@@ -371,6 +406,15 @@ module VagrantPlugins
371
406
  end
372
407
 
373
408
  # Returns a list of available host only interfaces.
409
+ # Each interface is represented as a Hash with the following details:
410
+ #
411
+ # {
412
+ # name: 'Host-Only', # Parallels Network ID
413
+ # bound_to: 'vnic1', # interface name
414
+ # ip: '10.37.129.2', # IP address of the interface
415
+ # netmask: '255.255.255.0', # netmask associated with the interface
416
+ # status: 'Up' # status of the interface
417
+ # }
374
418
  #
375
419
  # @return [Array<Symbol => String>]
376
420
  def read_host_only_interfaces
@@ -387,7 +431,7 @@ module VagrantPlugins
387
431
  end
388
432
 
389
433
  if shared_ifaces.empty?
390
- raise Errors::SharedAdapterNotFound
434
+ raise Errors::SharedInterfaceNotFound
391
435
  end
392
436
 
393
437
  shared_ifaces.values.first.fetch('mac', nil)
@@ -421,11 +465,7 @@ module VagrantPlugins
421
465
  #
422
466
  # @return [String] Shared network ID
423
467
  def read_shared_network_id
424
- # There should be only one Shared interface
425
- shared_net = read_virtual_networks.detect do |net|
426
- net['Type'] == 'shared'
427
- end
428
- shared_net.fetch('Network ID')
468
+ 'Shared'
429
469
  end
430
470
 
431
471
  # Returns info about shared network interface.
@@ -537,7 +577,11 @@ module VagrantPlugins
537
577
  # @param [String] uuid Name or UUID of the target VM
538
578
  # @param [String] snapshot_id Snapshot ID
539
579
  def restore_snapshot(uuid, snapshot_id)
540
- execute_prlctl('snapshot-switch', uuid, '-i', snapshot_id)
580
+ # Sometimes this command fails with 'Data synchronization is currently
581
+ # in progress'. Just wait and retry.
582
+ retryable(on: VagrantPlugins::Parallels::Errors::ExecutionError, tries: 2, sleep: 2) do
583
+ execute_prlctl('snapshot-switch', uuid, '-i', snapshot_id)
584
+ end
541
585
  end
542
586
 
543
587
  # Resumes the virtual machine.