vagrant-parallels 1.5.1 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +7 -4
  3. data/CHANGELOG.md +33 -0
  4. data/Gemfile +2 -2
  5. data/README.md +1 -1
  6. data/debug.log +1237 -1
  7. data/lib/vagrant-parallels/action.rb +8 -0
  8. data/lib/vagrant-parallels/action/box_register.rb +113 -0
  9. data/lib/vagrant-parallels/action/box_unregister.rb +43 -0
  10. data/lib/vagrant-parallels/action/export.rb +36 -35
  11. data/lib/vagrant-parallels/action/forward_ports.rb +32 -18
  12. data/lib/vagrant-parallels/action/import.rb +59 -106
  13. data/lib/vagrant-parallels/action/network.rb +17 -13
  14. data/lib/vagrant-parallels/action/prepare_clone_snapshot.rb +67 -0
  15. data/lib/vagrant-parallels/action/set_name.rb +1 -1
  16. data/lib/vagrant-parallels/action/snapshot_delete.rb +25 -0
  17. data/lib/vagrant-parallels/action/snapshot_restore.rb +23 -0
  18. data/lib/vagrant-parallels/action/snapshot_save.rb +23 -0
  19. data/lib/vagrant-parallels/cap.rb +63 -0
  20. data/lib/vagrant-parallels/config.rb +7 -3
  21. data/lib/vagrant-parallels/driver/base.rb +61 -28
  22. data/lib/vagrant-parallels/driver/meta.rb +20 -10
  23. data/lib/vagrant-parallels/driver/pd_11.rb +0 -21
  24. data/lib/vagrant-parallels/errors.rb +14 -6
  25. data/lib/vagrant-parallels/guest_cap/darwin/install_parallels_tools.rb +34 -0
  26. data/lib/vagrant-parallels/plugin.rb +23 -8
  27. data/lib/vagrant-parallels/version.rb +1 -1
  28. data/locales/en.yml +31 -17
  29. data/test/acceptance/provider/linked_clone_spec.rb +6 -2
  30. data/test/acceptance/skeletons/linked_clone/Vagrantfile +1 -1
  31. data/test/unit/base.rb +1 -0
  32. data/test/unit/cap_test.rb +96 -0
  33. data/test/unit/support/shared/pd_driver_examples.rb +7 -10
  34. metadata +12 -6
  35. data/lib/vagrant-parallels/cap/forwarded_ports.rb +0 -22
  36. data/lib/vagrant-parallels/cap/host_address.rb +0 -15
  37. data/lib/vagrant-parallels/cap/nic_mac_addresses.rb +0 -17
  38. data/lib/vagrant-parallels/cap/public_address.rb +0 -15
@@ -14,6 +14,11 @@ module VagrantPlugins
14
14
  # We use forwardable to do all our driver forwarding
15
15
  extend Forwardable
16
16
 
17
+ # We cache the Parallels Desktop version here once we have one,
18
+ # since during the execution of Vagrant, it likely doesn't change.
19
+ @@version = nil
20
+ @@version_lock = Mutex.new
21
+
17
22
  # The UUID of the virtual machine we represent
18
23
  attr_reader :uuid
19
24
 
@@ -29,23 +34,26 @@ module VagrantPlugins
29
34
 
30
35
  # Read and assign the version of Parallels Desktop we know which
31
36
  # specific driver to instantiate.
32
- @version = read_version || ''
33
-
37
+ @@version_lock.synchronize do
38
+ @@version = read_version
39
+ end
40
+
34
41
  # Instantiate the proper version driver for Parallels Desktop
35
- @logger.debug("Finding driver for Parallels Desktop version: #{@version}")
42
+ @logger.debug("Finding driver for Parallels Desktop version: #{@@version}")
36
43
 
44
+ major_ver = @@version.split('.').first.to_i
37
45
  driver_klass =
38
- case @version.split('.').first
39
- when '8' then PD_8
40
- when '9' then PD_9
41
- when '10' then PD_10
42
- when '11' then PD_11
43
- else raise Errors::ParallelsUnsupportedVersion
46
+ case major_ver
47
+ when 1..7 then raise Errors::ParallelsUnsupportedVersion
48
+ when 8 then PD_8
49
+ when 9 then PD_9
50
+ when 10 then PD_10
51
+ else PD_11
44
52
  end
45
53
 
46
54
  # Starting since PD 11 only Pro and Business editions have CLI
47
55
  # functionality and can be used with Vagrant.
48
- if @version.split('.').first.to_i >= 11
56
+ if major_ver >= 11
49
57
  edition = read_edition
50
58
  if !edition || !%w(any pro business).include?(edition)
51
59
  raise Errors::ParallelsUnsupportedEdition
@@ -54,6 +62,7 @@ module VagrantPlugins
54
62
 
55
63
  @logger.info("Using Parallels driver: #{driver_klass}")
56
64
  @driver = driver_klass.new(@uuid)
65
+ @version = @@version
57
66
 
58
67
  if @uuid
59
68
  # Verify the VM exists, and if it doesn't, then don't worry
@@ -77,6 +86,7 @@ module VagrantPlugins
77
86
  :forward_ports,
78
87
  :halt,
79
88
  :clone_vm,
89
+ :list_snapshots,
80
90
  :read_bridged_interfaces,
81
91
  :read_current_snapshot,
82
92
  :read_forwarded_ports,
@@ -14,27 +14,6 @@ module VagrantPlugins
14
14
 
15
15
  @logger = Log4r::Logger.new('vagrant_parallels::driver::pd_11')
16
16
  end
17
-
18
- def create_snapshot(uuid, options)
19
- args = ['snapshot', uuid]
20
- args.concat(['--name', options[:name]]) if options[:name]
21
- args.concat(['--description', options[:desc]]) if options[:desc]
22
-
23
- stdout = execute_prlctl(*args)
24
- if stdout =~ /\{([\w-]+)\}/
25
- return $1
26
- end
27
-
28
- raise Errors::SnapshotIdNotDetected, stdout: stdout
29
- end
30
-
31
- def read_current_snapshot(uuid)
32
- if execute_prlctl('snapshot-list', uuid) =~ /\*\{([\w-]+)\}/
33
- return $1
34
- end
35
-
36
- nil
37
- end
38
17
  end
39
18
  end
40
19
  end
@@ -7,6 +7,14 @@ module VagrantPlugins
7
7
  error_namespace('vagrant_parallels.errors')
8
8
  end
9
9
 
10
+ class BoxImageNotFound < VagrantParallelsError
11
+ error_key(:box_image_not_found)
12
+ end
13
+
14
+ class BoxIDNotFound < VagrantParallelsError
15
+ error_key(:box_id_not_found)
16
+ end
17
+
10
18
  class DhcpLeasesNotAccessible < VagrantParallelsError
11
19
  error_key(:dhcp_leases_file_not_accessible)
12
20
  end
@@ -51,10 +59,6 @@ module VagrantPlugins
51
59
  error_key(:parallels_tools_iso_not_found)
52
60
  end
53
61
 
54
- class ParallelsTplNameNotFound < VagrantParallelsError
55
- error_key(:parallels_tpl_name_not_found)
56
- end
57
-
58
62
  class ParallelsVMOptionNotFound < VagrantParallelsError
59
63
  error_key(:parallels_vm_option_not_found)
60
64
  end
@@ -75,8 +79,12 @@ module VagrantPlugins
75
79
  error_key(:snapshot_id_not_detected)
76
80
  end
77
81
 
78
- class VMImportFailure < VagrantParallelsError
79
- error_key(:vm_import_failure)
82
+ class SnapshotNotFound < VagrantParallelsError
83
+ error_key(:snapshot_not_found)
84
+ end
85
+
86
+ class VMCloneFailure < VagrantParallelsError
87
+ error_key(:vm_clone_failure)
80
88
  end
81
89
 
82
90
  class VMNameExists < VagrantParallelsError
@@ -0,0 +1,34 @@
1
+ module VagrantPlugins
2
+ module Parallels
3
+ module GuestDarwinCap
4
+ class InstallParallelsTools
5
+
6
+ def self.install_parallels_tools(machine)
7
+ machine.communicate.tap do |comm|
8
+ tools_iso_path = File.expand_path(
9
+ machine.provider.driver.read_guest_tools_iso_path('darwin'),
10
+ machine.env.root_path
11
+ )
12
+ remote_file = '/tmp/prl-tools-mac.iso'
13
+ mount_point = "/media/prl-tools-lin_#{rand(100000)}/"
14
+
15
+ comm.upload(tools_iso_path, remote_file)
16
+
17
+ # Create mount point directory if needed
18
+ if !comm.test("test -d \"#{mount_point}\"", :sudo => true)
19
+ comm.sudo("mkdir -p \"#{mount_point}\"")
20
+ end
21
+
22
+ # Mount ISO and install Parallels Tools
23
+ comm.sudo("hdiutil attach #{remote_file} -mountpoint #{mount_point}")
24
+ comm.sudo("installer -pkg '#{mount_point}/Install.app/Contents/Resources/Install.mpkg' -target /")
25
+ comm.sudo("hdiutil detach '#{mount_point}'")
26
+
27
+ comm.sudo("rm -Rf \"#{mount_point}\"")
28
+ comm.sudo("rm -f \"#{remote_file}\"")
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -6,8 +6,8 @@ end
6
6
 
7
7
  # This is a sanity check to make sure no one is attempting to install
8
8
  # this into an early Vagrant version.
9
- if Vagrant::VERSION < '1.5.0'
10
- raise 'The Vagrant Parallels plugin is only compatible with Vagrant 1.5+'
9
+ if Gem::Version.new(Vagrant::VERSION).release < Gem::Version.new('1.8.0')
10
+ raise 'The installed version of Vagrant Parallels plugin is only compatible with Vagrant 1.8+'
11
11
  end
12
12
 
13
13
  module VagrantPlugins
@@ -33,6 +33,11 @@ module VagrantPlugins
33
33
  Config
34
34
  end
35
35
 
36
+ guest_capability(:darwin, :install_parallels_tools) do
37
+ require_relative 'guest_cap/darwin/install_parallels_tools'
38
+ GuestDarwinCap::InstallParallelsTools
39
+ end
40
+
36
41
  guest_capability(:darwin, :mount_parallels_shared_folder) do
37
42
  require_relative 'guest_cap/darwin/mount_parallels_shared_folder'
38
43
  GuestDarwinCap::MountParallelsSharedFolder
@@ -64,18 +69,28 @@ module VagrantPlugins
64
69
  end
65
70
 
66
71
  provider_capability(:parallels, :public_address) do
67
- require_relative 'cap/public_address'
68
- Cap::PublicAddress
72
+ require_relative 'cap'
73
+ Cap
74
+ end
75
+
76
+ provider_capability(:parallels, :forwarded_ports) do
77
+ require_relative 'cap'
78
+ Cap
69
79
  end
70
80
 
71
81
  provider_capability(:parallels, :host_address) do
72
- require_relative 'cap/host_address'
73
- Cap::HostAddress
82
+ require_relative 'cap'
83
+ Cap
74
84
  end
75
85
 
76
86
  provider_capability(:parallels, :nic_mac_addresses) do
77
- require_relative 'cap/nic_mac_addresses'
78
- Cap::NicMacAddresses
87
+ require_relative 'cap'
88
+ Cap
89
+ end
90
+
91
+ provider_capability(:parallels, :snapshot_list) do
92
+ require_relative 'cap'
93
+ Cap
79
94
  end
80
95
 
81
96
  synced_folder(:parallels) do
@@ -1,5 +1,5 @@
1
1
  module VagrantPlugins
2
2
  module Parallels
3
- VERSION = '1.5.1'
3
+ VERSION = '1.6.0'
4
4
  end
5
5
  end
data/locales/en.yml CHANGED
@@ -7,6 +7,18 @@ en:
7
7
  # Translations for exception classes
8
8
  #-------------------------------------------------------------------------------
9
9
  errors:
10
+ box_id_not_found: |-
11
+ Parallels provider couldn't fetch the box image ID. This is usually because
12
+ the "config.pvs" file is corrupted or doesn't exist. Please remove the box,
13
+ re-add it, and try again.
14
+
15
+ Box: "%{name}"
16
+ Box VM config: "%{config}"
17
+
18
+ box_image_not_found: |-
19
+ Parallels VM image (*.pvm) could not be found in the directory of
20
+ '%{name}' box. This is usually because the image has been removed manually.
21
+ Please remove the box, re-add it, and try again.
10
22
  dhcp_leases_file_not_accessible: |-
11
23
  Parallels DHCP leases file is not accessible. The Parallels provider
12
24
  uses it to detect an IP address of virtual machine. This file must be
@@ -67,12 +79,6 @@ en:
67
79
  reinstall Parallels Desktop.
68
80
 
69
81
  Expected ISO path: "%{iso_path}"
70
- parallels_tpl_name_not_found: |-
71
- The VM import failed! Template name not found. Please verify that
72
- the box you're using is not corrupted and try again.
73
-
74
- Template config path: "%{config_path}"
75
-
76
82
  parallels_vm_option_not_found: |-
77
83
  Could not find a required option of Parallels Desktop virtual machine:
78
84
  %{vm_option}
@@ -95,17 +101,22 @@ en:
95
101
  Desktop for Mac. Please, be aware while choosing the edition to upgrade to.
96
102
  snapshot_id_not_detected: |-
97
103
  ID of the newly created shapshod could not be detected. This is an
98
- internal error that users should never see. Please report a bug.
104
+ internal error that users should never see. Please report a bug to
105
+ Parallels provider.
99
106
 
100
107
  stdout: %{stdout}
108
+ snapshot_not_found: |-
109
+ The 'linked_clone_snapshot' specified could not be found. Please double
110
+ check and try again.
111
+
112
+ Snapshot ID: %{snapshot}
101
113
  shared_adapter_not_found: |-
102
114
  Shared network adapter was not found in your virtual machine configuration.
103
115
  It is required to communicate with VM and forward ports. Please check
104
116
  network configuration in your Vagrantfile.
105
- vm_import_failure: |-
106
- The VM import failed! Please verify that the box you're using is not
117
+ vm_clone_failure: |-
118
+ The VM cloning failed! Please ensure that the box you're using is not
107
119
  corrupted and try again.
108
-
109
120
  vm_name_exists: |-
110
121
  Parallels Desktop virtual machine with the name '%{name}' already exists.
111
122
  Please use another name or delete the machine with the existing
@@ -170,6 +181,12 @@ en:
170
181
  #-------------------------------------------------------------------------------
171
182
  actions:
172
183
  vm:
184
+ box:
185
+ register: Registering VM image from the base box '%{name}'...
186
+ unregister: Unregistering the box VM image...
187
+ clone:
188
+ full: Cloning new virtual machine...
189
+ linked: Creating new virtual machine as a linked clone...
173
190
  handle_guest_tools:
174
191
  cant_install: |-
175
192
  Vagrant doesn't support installing Parallels Tools for the guest OS
@@ -181,24 +198,21 @@ en:
181
198
  Installing the proper version of Parallels Tools. This may take a few minutes...
182
199
  not_detected: |-
183
200
  Parallels Tools were not detected on this VM! They are required
184
- for forwarded ports, shared folders, host only networking and more.
185
- If SSH fails or shared folders are not working on this machine,
186
- please install Parallels Tools within the virtual machine and
187
- reload your VM.
201
+ for shared folders, time sync and more. If shared folders are not
202
+ working on this machine, please install Parallels Tools within the
203
+ virtual machine and reload your VM.
188
204
  rebooting: |-
189
205
  Parallels Tools have been installed. Rebooting the VM...
190
206
  outdated: |-
191
207
  Parallels Tools installed on this VM are outdated! In most cases
192
208
  this is fine but in rare cases it can cause things such as shared
193
209
  folders to not work properly. If you see shared folder errors,
194
- please update Parallels Tools within the virtual machine and
210
+ please update Parallels Tools within the virtual machine and
195
211
  reload your VM.
196
212
  export:
197
213
  compacting: Compacting exported HDDs...
198
214
  forward_ports:
199
215
  forwarding_entry: |-
200
216
  %{guest_port} => %{host_port}
201
- import:
202
- importing_linked: Importing base box '%{name}' as a linked clone...
203
217
  sane_defaults:
204
218
  setting: Setting the default configuration for VM...
@@ -10,7 +10,6 @@ shared_examples 'provider/linked_clone' do |provider, options|
10
10
  before do
11
11
  environment.skeleton('linked_clone')
12
12
  assert_execute('vagrant', 'box', 'add', 'basic', options[:box])
13
- assert_execute('vagrant', 'up', "--provider=#{provider}")
14
13
  end
15
14
 
16
15
  after do
@@ -18,7 +17,12 @@ shared_examples 'provider/linked_clone' do |provider, options|
18
17
  end
19
18
 
20
19
  it 'creates machine as linked clone' do
21
- status('Test: machine is running after up')
20
+ status('Test: machine is created as a linked clone')
21
+ result = execute('vagrant', 'up', "--provider=#{provider}")
22
+ expect(result).to exit_with(0)
23
+ expect(result.stdout).to match(/linked clone/)
24
+
25
+ status('Test: machine is available by ssh')
22
26
  result = execute('vagrant', 'ssh', '-c', 'echo foo')
23
27
  expect(result).to exit_with(0)
24
28
  expect(result.stdout).to match(/foo\n$/)
@@ -2,6 +2,6 @@ Vagrant.configure('2') do |config|
2
2
  config.vm.box = 'basic'
3
3
 
4
4
  config.vm.provider 'parallels' do |prl|
5
- prl.use_linked_clone = true
5
+ prl.linked_clone = true
6
6
  end
7
7
  end
data/test/unit/base.rb CHANGED
@@ -5,6 +5,7 @@ require 'rspec/autorun'
5
5
  # classes to test.
6
6
  require 'vagrant'
7
7
  require 'vagrant-parallels'
8
+ require 'vagrant-spec/unit'
8
9
 
9
10
  # Add the test directory to the load path
10
11
  $:.unshift File.expand_path('../../', __FILE__)
@@ -0,0 +1,96 @@
1
+ require_relative 'base'
2
+
3
+ require 'vagrant-parallels/cap'
4
+
5
+ describe VagrantPlugins::Parallels::Cap do
6
+ include_context 'vagrant-unit'
7
+
8
+ let(:iso_env) do
9
+ # We have to create a Vagrantfile so there is a root path
10
+ env = isolated_environment
11
+ env.vagrantfile('')
12
+ env.create_vagrant_env
13
+ end
14
+
15
+ let(:machine) do
16
+ iso_env.machine(iso_env.machine_names[0], :dummy).tap do |m|
17
+ m.provider.stub(driver: driver)
18
+ m.stub(state: state)
19
+ end
20
+ end
21
+
22
+ let(:driver) { double('driver') }
23
+ let(:state) { double('state', id: :running) }
24
+
25
+ describe '#forwarded_ports' do
26
+ it 'returns all the forwarded ports' do
27
+ allow(driver).to receive(:read_forwarded_ports).and_return([
28
+ { hostport: 123, guestport: 456 },
29
+ { hostport: 245, guestport: 245 }
30
+ ])
31
+
32
+ expect(described_class.forwarded_ports(machine)).to eq({
33
+ 123 => 456,
34
+ 245 => 245,
35
+ })
36
+ end
37
+
38
+ it 'returns nil when the machine is not running' do
39
+ allow(state).to receive(:id).and_return(:stopped)
40
+ expect(described_class.forwarded_ports(machine)).to be(nil)
41
+ end
42
+ end
43
+
44
+ describe '#host_address' do
45
+ it "returns host's IP of Shared interface" do
46
+ allow(driver).to receive(:read_shared_interface).and_return(ip: '1.2.3.4')
47
+ expect(described_class.host_address(machine)).to eq('1.2.3.4')
48
+ end
49
+ end
50
+
51
+ describe '#nic_mac_addresses' do
52
+ it 'returns a hash with MAC addresses' do
53
+ allow(driver).to receive(:read_mac_addresses).and_return(
54
+ ['001A2B3C4D5E', '005E4D3C2B1A'])
55
+ expect(described_class.nic_mac_addresses(machine)).to eq({
56
+ 1 => '001A2B3C4D5E',
57
+ 2 => '005E4D3C2B1A'
58
+ })
59
+ end
60
+
61
+ it 'returns an empty hash when there are no NICs' do
62
+ allow(driver).to receive(:read_mac_addresses).and_return([])
63
+ expect(described_class.nic_mac_addresses(machine)).to eq({})
64
+ end
65
+ end
66
+
67
+ describe '#public_address' do
68
+ it "returns VM's IP" do
69
+ allow(machine).to receive(:ssh_info).and_return(host: '1.2.3.4')
70
+ expect(described_class.public_address(machine)).to eq('1.2.3.4')
71
+ end
72
+
73
+ it "returns nil when the machine is not running" do
74
+ allow(state).to receive(:id).and_return(:stopped)
75
+ expect(described_class.public_address(machine)).to be(nil)
76
+ end
77
+
78
+ it "returns nil when there is no ssh info" do
79
+ allow(machine).to receive(:ssh_info).and_return(nil)
80
+ expect(described_class.public_address(machine)).to be(nil)
81
+ end
82
+ end
83
+
84
+ describe '#snapshot_list' do
85
+ it 'returns a list of snapshots' do
86
+ allow(machine).to receive(:id).and_return('foo')
87
+ allow(driver).to receive(:list_snapshots).with('foo').and_return({
88
+ 'snap_name_1' => 'snap_uuid_1',
89
+ 'snap_name_2' => 'snap_uuid_2'
90
+ })
91
+
92
+ expect(described_class.snapshot_list(machine)).to eq(
93
+ ['snap_name_1', 'snap_name_2'])
94
+ end
95
+ end
96
+ end