vagrant-parallels 1.5.1 → 1.6.0
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.
- checksums.yaml +4 -4
- data/.travis.yml +7 -4
- data/CHANGELOG.md +33 -0
- data/Gemfile +2 -2
- data/README.md +1 -1
- data/debug.log +1237 -1
- data/lib/vagrant-parallels/action.rb +8 -0
- data/lib/vagrant-parallels/action/box_register.rb +113 -0
- data/lib/vagrant-parallels/action/box_unregister.rb +43 -0
- data/lib/vagrant-parallels/action/export.rb +36 -35
- data/lib/vagrant-parallels/action/forward_ports.rb +32 -18
- data/lib/vagrant-parallels/action/import.rb +59 -106
- data/lib/vagrant-parallels/action/network.rb +17 -13
- data/lib/vagrant-parallels/action/prepare_clone_snapshot.rb +67 -0
- data/lib/vagrant-parallels/action/set_name.rb +1 -1
- data/lib/vagrant-parallels/action/snapshot_delete.rb +25 -0
- data/lib/vagrant-parallels/action/snapshot_restore.rb +23 -0
- data/lib/vagrant-parallels/action/snapshot_save.rb +23 -0
- data/lib/vagrant-parallels/cap.rb +63 -0
- data/lib/vagrant-parallels/config.rb +7 -3
- data/lib/vagrant-parallels/driver/base.rb +61 -28
- data/lib/vagrant-parallels/driver/meta.rb +20 -10
- data/lib/vagrant-parallels/driver/pd_11.rb +0 -21
- data/lib/vagrant-parallels/errors.rb +14 -6
- data/lib/vagrant-parallels/guest_cap/darwin/install_parallels_tools.rb +34 -0
- data/lib/vagrant-parallels/plugin.rb +23 -8
- data/lib/vagrant-parallels/version.rb +1 -1
- data/locales/en.yml +31 -17
- data/test/acceptance/provider/linked_clone_spec.rb +6 -2
- data/test/acceptance/skeletons/linked_clone/Vagrantfile +1 -1
- data/test/unit/base.rb +1 -0
- data/test/unit/cap_test.rb +96 -0
- data/test/unit/support/shared/pd_driver_examples.rb +7 -10
- metadata +12 -6
- data/lib/vagrant-parallels/cap/forwarded_ports.rb +0 -22
- data/lib/vagrant-parallels/cap/host_address.rb +0 -15
- data/lib/vagrant-parallels/cap/nic_mac_addresses.rb +0 -17
- data/lib/vagrant-parallels/cap/public_address.rb +0 -15
@@ -161,18 +161,23 @@ module VagrantPlugins
|
|
161
161
|
@logger.debug("Bridge was directly specified in config, searching for: #{config[:bridge]}")
|
162
162
|
|
163
163
|
# Search for a matching bridged interface
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
164
|
+
Array(config[:bridge]).each do |bridge|
|
165
|
+
bridge = bridge.downcase if bridge.respond_to?(:downcase)
|
166
|
+
bridgedifs.each do |interface|
|
167
|
+
if bridge === interface[:name].downcase
|
168
|
+
@logger.debug('Specific bridge found as configured in the Vagrantfile. Using it.')
|
169
|
+
chosen_bridge = interface[:name]
|
170
|
+
break
|
171
|
+
end
|
169
172
|
end
|
173
|
+
break if chosen_bridge
|
170
174
|
end
|
171
175
|
|
172
176
|
# If one wasn't found, then we notify the user here.
|
173
177
|
if !chosen_bridge
|
174
|
-
@env[:ui].info I18n.t(
|
175
|
-
|
178
|
+
@env[:ui].info I18n.t(
|
179
|
+
'vagrant.actions.vm.bridged_networking.specific_not_found',
|
180
|
+
bridge: config[:bridge])
|
176
181
|
end
|
177
182
|
end
|
178
183
|
|
@@ -188,14 +193,14 @@ module VagrantPlugins
|
|
188
193
|
else
|
189
194
|
# More than one bridgable interface requires a user decision, so
|
190
195
|
# show options to choose from.
|
191
|
-
@env[:ui].info I18n.t(
|
192
|
-
|
196
|
+
@env[:ui].info I18n.t(
|
197
|
+
'vagrant.actions.vm.bridged_networking.available', prefix: false)
|
193
198
|
bridgedifs.each_index do |index|
|
194
199
|
interface = bridgedifs[index]
|
195
|
-
@env[:ui].info("#{index + 1}) #{interface[:name]}", :
|
200
|
+
@env[:ui].info("#{index + 1}) #{interface[:name]}", prefix: false)
|
196
201
|
end
|
197
202
|
@env[:ui].info(I18n.t(
|
198
|
-
|
203
|
+
'vagrant.actions.vm.bridged_networking.choice_help')+"\n")
|
199
204
|
|
200
205
|
# The range of valid choices
|
201
206
|
valid = Range.new(1, bridgedifs.length)
|
@@ -410,8 +415,7 @@ module VagrantPlugins
|
|
410
415
|
if net_nums.empty?
|
411
416
|
'vagrant-vnet0'
|
412
417
|
else
|
413
|
-
net_nums.
|
414
|
-
free_names = Array(0..net_nums.last.next) - net_nums
|
418
|
+
free_names = Array(0..net_nums.max) - net_nums
|
415
419
|
"vagrant-vnet#{free_names.first}"
|
416
420
|
end
|
417
421
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
|
3
|
+
require 'digest/md5'
|
4
|
+
|
5
|
+
module VagrantPlugins
|
6
|
+
module Parallels
|
7
|
+
module Action
|
8
|
+
class PrepareCloneSnapshot
|
9
|
+
@@lock = Mutex.new
|
10
|
+
|
11
|
+
def initialize(app, env)
|
12
|
+
@app = app
|
13
|
+
@logger = Log4r::Logger.new('vagrant_parallels::action::prepare_clone_snapshot')
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(env)
|
17
|
+
if !env[:clone_id]
|
18
|
+
@logger.info('No source VM for cloning, skip snapshot preparing')
|
19
|
+
return @app.call(env)
|
20
|
+
end
|
21
|
+
|
22
|
+
# If we're not doing a linked clone, snapshots don't matter
|
23
|
+
if !env[:machine].provider_config.linked_clone \
|
24
|
+
|| env[:machine].provider.pd_version_satisfies?('< 11')
|
25
|
+
return @app.call(env)
|
26
|
+
end
|
27
|
+
|
28
|
+
# We lock so that we don't snapshot in parallel
|
29
|
+
@@lock.synchronize do
|
30
|
+
lock_key = Digest::MD5.hexdigest("#{env[:clone_id]}-snapshot")
|
31
|
+
env[:machine].env.lock(lock_key, retry: true) do
|
32
|
+
prepare_snapshot(env)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Continue
|
37
|
+
@app.call(env)
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
def prepare_snapshot(env)
|
43
|
+
set_snapshot = env[:machine].provider_config.linked_clone_snapshot
|
44
|
+
env[:clone_snapshot] = set_snapshot || 'vagrant_linked_clone'
|
45
|
+
|
46
|
+
# Get the snapshots. We're done if it already exists
|
47
|
+
snapshots = env[:machine].provider.driver.list_snapshots(env[:clone_id])
|
48
|
+
|
49
|
+
if snapshots.include?(env[:clone_snapshot])
|
50
|
+
env[:clone_snapshot_id] = snapshots[env[:clone_snapshot]]
|
51
|
+
@logger.info('Linked clone snapshot already exists, doing nothing')
|
52
|
+
return
|
53
|
+
end
|
54
|
+
|
55
|
+
# We've specified the snapshot name but it doesn't exist
|
56
|
+
if set_snapshot
|
57
|
+
raise Errors::SnapshotNotFound, snapshot: set_snapshot
|
58
|
+
end
|
59
|
+
|
60
|
+
@logger.info('Creating a new snapshot for linked clone')
|
61
|
+
env[:clone_snapshot_id] = env[:machine].provider.driver.create_snapshot(
|
62
|
+
env[:clone_id], env[:clone_snapshot])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -37,7 +37,7 @@ module VagrantPlugins
|
|
37
37
|
else
|
38
38
|
env[:ui].info(I18n.t(
|
39
39
|
'vagrant.actions.vm.set_name.setting_name', name: name))
|
40
|
-
env[:machine].provider.driver.set_name(name)
|
40
|
+
env[:machine].provider.driver.set_name(env[:machine].id, name)
|
41
41
|
end
|
42
42
|
|
43
43
|
# Create the sentinel
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module Parallels
|
3
|
+
module Action
|
4
|
+
class SnapshotDelete
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
snapshots = env[:machine].provider.driver.list_snapshots(env[:machine].id)
|
11
|
+
snapshot_id = snapshots[env[:snapshot_name]]
|
12
|
+
|
13
|
+
env[:ui].info I18n.t('vagrant.actions.vm.snapshot.deleting',
|
14
|
+
name: env[:snapshot_name])
|
15
|
+
env[:machine].provider.driver.delete_snapshot(
|
16
|
+
env[:machine].id, snapshot_id)
|
17
|
+
|
18
|
+
env[:ui].success I18n.t('vagrant.actions.vm.snapshot.deleted',
|
19
|
+
name: env[:snapshot_name])
|
20
|
+
@app.call(env)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module Parallels
|
3
|
+
module Action
|
4
|
+
class SnapshotRestore
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
snapshots = env[:machine].provider.driver.list_snapshots(env[:machine].id)
|
11
|
+
snapshot_id = snapshots[env[:snapshot_name]]
|
12
|
+
|
13
|
+
env[:ui].info I18n.t('vagrant.actions.vm.snapshot.restoring',
|
14
|
+
name: env[:snapshot_name])
|
15
|
+
env[:machine].provider.driver.restore_snapshot(
|
16
|
+
env[:machine].id, snapshot_id)
|
17
|
+
|
18
|
+
@app.call(env)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module Parallels
|
3
|
+
module Action
|
4
|
+
class SnapshotSave
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
env[:ui].info I18n.t('vagrant.actions.vm.snapshot.saving',
|
11
|
+
name: env[:snapshot_name])
|
12
|
+
env[:machine].provider.driver.create_snapshot(
|
13
|
+
env[:machine].id, env[:snapshot_name])
|
14
|
+
|
15
|
+
env[:ui].success I18n.t('vagrant.actions.vm.snapshot.saved',
|
16
|
+
name: env[:snapshot_name])
|
17
|
+
|
18
|
+
@app.call(env)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module Parallels
|
3
|
+
module Cap
|
4
|
+
# Reads the forwarded ports that currently exist on the machine
|
5
|
+
# itself.
|
6
|
+
#
|
7
|
+
# This also may not match up with configured forwarded ports, because
|
8
|
+
# Vagrant auto port collision fixing may have taken place.
|
9
|
+
#
|
10
|
+
# @return [Hash<Integer, Integer>] Host => Guest port mappings.
|
11
|
+
def self.forwarded_ports(machine)
|
12
|
+
return nil if machine.state.id != :running
|
13
|
+
|
14
|
+
{}.tap do |result|
|
15
|
+
machine.provider.driver.read_forwarded_ports.each do |fp|
|
16
|
+
result[fp[:hostport]] = fp[:guestport]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns host's IP address that can be used to access the host machine
|
22
|
+
# from the VM.
|
23
|
+
#
|
24
|
+
# @return [String] Host's IP address
|
25
|
+
def self.host_address(machine)
|
26
|
+
|
27
|
+
shared_iface = machine.provider.driver.read_shared_interface
|
28
|
+
return shared_iface[:ip] if shared_iface
|
29
|
+
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
|
33
|
+
# Reads the network interface card MAC addresses and returns them.
|
34
|
+
#
|
35
|
+
# @return [Hash<Integer, String>] Adapter => MAC address
|
36
|
+
def self.nic_mac_addresses(machine)
|
37
|
+
nic_macs = machine.provider.driver.read_mac_addresses
|
38
|
+
|
39
|
+
# Make numeration starting from 1, as it is expected in Vagrant.
|
40
|
+
Hash[nic_macs.map.with_index{ |mac, index| [index+1, mac] }]
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns guest's IP address that can be used to access the VM from the
|
44
|
+
# host machine.
|
45
|
+
#
|
46
|
+
# @return [String] Guest's IP address
|
47
|
+
def self.public_address(machine)
|
48
|
+
return nil if machine.state.id != :running
|
49
|
+
|
50
|
+
ssh_info = machine.ssh_info
|
51
|
+
return nil if !ssh_info
|
52
|
+
ssh_info[:host]
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns a list of the snapshots that are taken on this machine.
|
56
|
+
#
|
57
|
+
# @return [Array<String>] Snapshot Name
|
58
|
+
def self.snapshot_list(machine)
|
59
|
+
machine.provider.driver.list_snapshots(machine.id).keys
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -6,7 +6,8 @@ module VagrantPlugins
|
|
6
6
|
attr_accessor :destroy_unused_network_interfaces
|
7
7
|
attr_accessor :functional_psf
|
8
8
|
attr_accessor :optimize_power_consumption
|
9
|
-
attr_accessor :
|
9
|
+
attr_accessor :linked_clone
|
10
|
+
attr_accessor :linked_clone_snapshot
|
10
11
|
attr_accessor :name
|
11
12
|
attr_reader :network_adapters
|
12
13
|
attr_accessor :regen_src_uuid
|
@@ -17,13 +18,15 @@ module VagrantPlugins
|
|
17
18
|
|
18
19
|
# Compatibility with old names
|
19
20
|
alias :regen_box_uuid= :regen_src_uuid=
|
21
|
+
alias :use_linked_clone= :linked_clone=
|
20
22
|
|
21
23
|
def initialize
|
22
24
|
@check_guest_tools = UNSET_VALUE
|
23
25
|
@customizations = []
|
24
26
|
@destroy_unused_network_interfaces = UNSET_VALUE
|
25
27
|
@functional_psf = UNSET_VALUE
|
26
|
-
@
|
28
|
+
@linked_clone = UNSET_VALUE
|
29
|
+
@linked_clone_snapshot = UNSET_VALUE
|
27
30
|
@network_adapters = {}
|
28
31
|
@name = UNSET_VALUE
|
29
32
|
@optimize_power_consumption = UNSET_VALUE
|
@@ -77,7 +80,8 @@ module VagrantPlugins
|
|
77
80
|
@functional_psf = true
|
78
81
|
end
|
79
82
|
|
80
|
-
@
|
83
|
+
@linked_clone = false if @linked_clone == UNSET_VALUE
|
84
|
+
@linked_clone_snapshot = nil if @linked_clone_snapshot == UNSET_VALUE
|
81
85
|
|
82
86
|
@name = nil if @name == UNSET_VALUE
|
83
87
|
|
@@ -55,12 +55,12 @@ module VagrantPlugins
|
|
55
55
|
# Makes a clone of the virtual machine.
|
56
56
|
#
|
57
57
|
# @param [String] src_name Name or UUID of the source VM or template.
|
58
|
-
# @param [String] dst_name Name of the destination VM.
|
59
58
|
# @param [<String => String>] options Options to clone virtual machine.
|
60
59
|
# @return [String] UUID of the new VM.
|
61
|
-
def clone_vm(src_name,
|
60
|
+
def clone_vm(src_name, options={})
|
61
|
+
dst_name = "vagrant_temp_#{(Time.now.to_f * 1000.0).to_i}_#{rand(100000)}"
|
62
|
+
|
62
63
|
args = ['clone', src_name, '--name', dst_name]
|
63
|
-
args << '--template' if options[:template]
|
64
64
|
args.concat(['--dst', options[:dst]]) if options[:dst]
|
65
65
|
|
66
66
|
# Linked clone options
|
@@ -127,11 +127,16 @@ module VagrantPlugins
|
|
127
127
|
|
128
128
|
# Creates a snapshot for the specified virtual machine.
|
129
129
|
#
|
130
|
-
# @param [String] uuid Name or UUID of the target VM
|
131
|
-
# @param [
|
130
|
+
# @param [String] uuid Name or UUID of the target VM
|
131
|
+
# @param [String] snapshot_name Snapshot name
|
132
132
|
# @return [String] ID of the created snapshot.
|
133
|
-
def create_snapshot(uuid,
|
134
|
-
|
133
|
+
def create_snapshot(uuid, snapshot_name)
|
134
|
+
stdout = execute_prlctl('snapshot', uuid, '--name', snapshot_name)
|
135
|
+
if stdout =~ /\{([\w-]+)\}/
|
136
|
+
return Regexp.last_match(1)
|
137
|
+
end
|
138
|
+
|
139
|
+
raise Errors::SnapshotIdNotDetected, stdout: stdout
|
135
140
|
end
|
136
141
|
|
137
142
|
# Deletes the virtual machine references by this driver.
|
@@ -148,6 +153,14 @@ module VagrantPlugins
|
|
148
153
|
end
|
149
154
|
end
|
150
155
|
|
156
|
+
# Deletes the specified snapshot
|
157
|
+
#
|
158
|
+
# @param [String] uuid Name or UUID of the target VM
|
159
|
+
# @param [String] snapshot_id Snapshot ID
|
160
|
+
def delete_snapshot(uuid, snapshot_id)
|
161
|
+
execute_prlctl('snapshot-delete', uuid, '--id', snapshot_id)
|
162
|
+
end
|
163
|
+
|
151
164
|
# Deletes any host only networks that aren't being used for anything.
|
152
165
|
def delete_unused_host_only_networks
|
153
166
|
raise NotImplementedError
|
@@ -203,6 +216,35 @@ module VagrantPlugins
|
|
203
216
|
raise NotImplementedError
|
204
217
|
end
|
205
218
|
|
219
|
+
# Lists all snapshots for the specified VM. Returns an empty hash if
|
220
|
+
# there are no snapshots.
|
221
|
+
#
|
222
|
+
# @param [String] uuid Name or UUID of the target VM.
|
223
|
+
# @return [<String => String>] {'Snapshot Name' => 'Snapshot UUID'}
|
224
|
+
def list_snapshots(uuid)
|
225
|
+
settings = read_settings(uuid)
|
226
|
+
snap_config = File.join(settings.fetch('Home'), 'Snapshots.xml')
|
227
|
+
|
228
|
+
# There are no snapshots, exit
|
229
|
+
return {} if !File.exist?(snap_config)
|
230
|
+
|
231
|
+
xml = Nokogiri::XML(File.read(snap_config))
|
232
|
+
snapshots = {}
|
233
|
+
|
234
|
+
# Loop over all 'SavedStateItem' and fetch 'Name' => 'ID' pairs
|
235
|
+
xml.xpath('//SavedStateItem').each do |snap|
|
236
|
+
snap_id = snap.attr('guid')
|
237
|
+
|
238
|
+
# The first entry is always empty (the base sate)
|
239
|
+
next if snap_id.empty?
|
240
|
+
|
241
|
+
snap_name = snap.at('Name').text
|
242
|
+
snapshots[snap_name] = snap_id
|
243
|
+
end
|
244
|
+
|
245
|
+
snapshots
|
246
|
+
end
|
247
|
+
|
206
248
|
# Halts the virtual machine (pulls the plug).
|
207
249
|
def halt(force=false)
|
208
250
|
args = ['stop', @uuid]
|
@@ -247,15 +289,6 @@ module VagrantPlugins
|
|
247
289
|
bridged_ifaces
|
248
290
|
end
|
249
291
|
|
250
|
-
# Returns current snapshot ID for the specified VM. Returns nil if
|
251
|
-
# the VM doesn't have any snapshot.
|
252
|
-
#
|
253
|
-
# @param [String] uuid Name or UUID of the target VM.
|
254
|
-
# @return [String]
|
255
|
-
def read_current_snapshot(uuid)
|
256
|
-
raise NotImplementedError
|
257
|
-
end
|
258
|
-
|
259
292
|
def read_forwarded_ports(global=false)
|
260
293
|
raise NotImplementedError
|
261
294
|
end
|
@@ -491,8 +524,9 @@ module VagrantPlugins
|
|
491
524
|
# Registers the virtual machine
|
492
525
|
#
|
493
526
|
# @param [String] pvm_file Path to the machine image (*.pvm)
|
494
|
-
|
495
|
-
|
527
|
+
# @param [Array<String>] opts List of options for "prlctl register"
|
528
|
+
def register(pvm_file, opts=[])
|
529
|
+
args = [@prlctl_path, 'register', pvm_file, *opts]
|
496
530
|
|
497
531
|
3.times do
|
498
532
|
result = raw(*args)
|
@@ -513,14 +547,12 @@ module VagrantPlugins
|
|
513
547
|
execute(*args)
|
514
548
|
end
|
515
549
|
|
516
|
-
#
|
550
|
+
# Switches the VM state to the specified snapshot
|
517
551
|
#
|
518
|
-
# @
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
execute_prlctl(*args).include?(uuid) ||
|
523
|
-
execute_prlctl(*args, '--template').include?(uuid)
|
552
|
+
# @param [String] uuid Name or UUID of the target VM
|
553
|
+
# @param [String] snapshot_id Snapshot ID
|
554
|
+
def restore_snapshot(uuid, snapshot_id)
|
555
|
+
execute_prlctl('snapshot-switch', uuid, '-i', snapshot_id)
|
524
556
|
end
|
525
557
|
|
526
558
|
# Resumes the virtual machine.
|
@@ -531,9 +563,10 @@ module VagrantPlugins
|
|
531
563
|
|
532
564
|
# Sets the name of the virtual machine.
|
533
565
|
#
|
534
|
-
# @param [String]
|
535
|
-
|
536
|
-
|
566
|
+
# @param [String] uuid VM name or UUID
|
567
|
+
# @param [String] new_name New VM name
|
568
|
+
def set_name(uuid, new_name)
|
569
|
+
execute_prlctl('set', uuid, '--name', new_name)
|
537
570
|
end
|
538
571
|
|
539
572
|
# Sets Power Consumption method.
|