vagrant-parallels 1.3.13 → 1.4.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.
- checksums.yaml +4 -4
- data/Vagrantfile +5 -6
- data/lib/vagrant-parallels/action/export.rb +7 -1
- data/lib/vagrant-parallels/action/import.rb +35 -3
- data/lib/vagrant-parallels/action/network.rb +8 -8
- data/lib/vagrant-parallels/config.rb +4 -0
- data/lib/vagrant-parallels/driver/base.rb +424 -53
- data/lib/vagrant-parallels/driver/meta.rb +8 -10
- data/lib/vagrant-parallels/driver/pd_10.rb +15 -21
- data/lib/vagrant-parallels/driver/pd_11.rb +41 -0
- data/lib/vagrant-parallels/driver/pd_8.rb +1 -397
- data/lib/vagrant-parallels/driver/pd_9.rb +1 -1
- data/lib/vagrant-parallels/errors.rb +4 -0
- data/lib/vagrant-parallels/plugin.rb +1 -0
- data/lib/vagrant-parallels/version.rb +1 -1
- data/locales/en.yml +9 -2
- data/tasks/acceptance.rake +2 -2
- data/tasks/test.rake +0 -4
- data/test/acceptance/provider/linked_clone_spec.rb +26 -0
- data/test/acceptance/skeletons/linked_clone/Vagrantfile +7 -0
- data/test/unit/support/shared/pd_driver_examples.rb +13 -18
- metadata +5 -2
@@ -1,8 +1,7 @@
|
|
1
|
-
require
|
1
|
+
require 'forwardable'
|
2
|
+
require 'log4r'
|
2
3
|
|
3
|
-
require
|
4
|
-
|
5
|
-
require File.expand_path("../base", __FILE__)
|
4
|
+
require File.expand_path('../base', __FILE__)
|
6
5
|
|
7
6
|
module VagrantPlugins
|
8
7
|
module Parallels
|
@@ -23,7 +22,7 @@ module VagrantPlugins
|
|
23
22
|
|
24
23
|
def initialize(uuid=nil)
|
25
24
|
# Setup the base
|
26
|
-
super()
|
25
|
+
super(uuid)
|
27
26
|
|
28
27
|
@logger = Log4r::Logger.new('vagrant_parallels::driver::meta')
|
29
28
|
@uuid = uuid
|
@@ -38,7 +37,7 @@ module VagrantPlugins
|
|
38
37
|
'8' => PD_8,
|
39
38
|
'9' => PD_9,
|
40
39
|
'10' => PD_10,
|
41
|
-
'11' =>
|
40
|
+
'11' => PD_11
|
42
41
|
}
|
43
42
|
|
44
43
|
driver_klass = nil
|
@@ -71,16 +70,17 @@ module VagrantPlugins
|
|
71
70
|
:clear_shared_folders,
|
72
71
|
:compact,
|
73
72
|
:create_host_only_network,
|
73
|
+
:create_snapshot,
|
74
74
|
:delete,
|
75
75
|
:delete_disabled_adapters,
|
76
76
|
:delete_unused_host_only_networks,
|
77
77
|
:disable_password_restrictions,
|
78
78
|
:enable_adapters,
|
79
|
-
:export,
|
80
79
|
:forward_ports,
|
81
80
|
:halt,
|
82
|
-
:
|
81
|
+
:clone_vm,
|
83
82
|
:read_bridged_interfaces,
|
83
|
+
:read_current_snapshot,
|
84
84
|
:read_forwarded_ports,
|
85
85
|
:read_guest_ip,
|
86
86
|
:read_guest_tools_state,
|
@@ -98,12 +98,10 @@ module VagrantPlugins
|
|
98
98
|
:read_vm_option,
|
99
99
|
:read_vms,
|
100
100
|
:read_vms_info,
|
101
|
-
:read_vms_paths,
|
102
101
|
:regenerate_src_uuid,
|
103
102
|
:register,
|
104
103
|
:resume,
|
105
104
|
:set_power_consumption_mode,
|
106
|
-
:set_mac_address,
|
107
105
|
:set_name,
|
108
106
|
:share_folders,
|
109
107
|
:ssh_ip,
|
@@ -32,7 +32,7 @@ module VagrantPlugins
|
|
32
32
|
# 'Shared'(vnic0) and 'Host-Only'(vnic1) are default in Parallels Desktop
|
33
33
|
# They should not be deleted anyway.
|
34
34
|
networks.keep_if do |net|
|
35
|
-
net['Type'] ==
|
35
|
+
net['Type'] == 'host-only' &&
|
36
36
|
net['Bound To'].match(/^(?>vnic|Parallels Host-Only #)(\d+)$/)[1].to_i >= 2
|
37
37
|
end
|
38
38
|
|
@@ -73,28 +73,28 @@ module VagrantPlugins
|
|
73
73
|
adapters.each do |adapter|
|
74
74
|
args = []
|
75
75
|
if existing_adapters.include? "net#{adapter[:adapter]}"
|
76
|
-
args.concat([
|
76
|
+
args.concat(['--device-set',"net#{adapter[:adapter]}", '--enable'])
|
77
77
|
else
|
78
|
-
args.concat([
|
78
|
+
args.concat(['--device-add', 'net'])
|
79
79
|
end
|
80
80
|
|
81
81
|
if adapter[:type] == :hostonly
|
82
|
-
args.concat([
|
82
|
+
args.concat(['--type', 'host', '--iface', adapter[:hostonly]])
|
83
83
|
elsif adapter[:type] == :bridged
|
84
|
-
args.concat([
|
84
|
+
args.concat(['--type', 'bridged', '--iface', adapter[:bridge]])
|
85
85
|
elsif adapter[:type] == :shared
|
86
|
-
args.concat([
|
86
|
+
args.concat(['--type', 'shared'])
|
87
87
|
end
|
88
88
|
|
89
89
|
if adapter[:mac_address]
|
90
|
-
args.concat([
|
90
|
+
args.concat(['--mac', adapter[:mac_address]])
|
91
91
|
end
|
92
92
|
|
93
93
|
if adapter[:nic_type]
|
94
|
-
args.concat([
|
94
|
+
args.concat(['--adapter-type', adapter[:nic_type].to_s])
|
95
95
|
end
|
96
96
|
|
97
|
-
execute_prlctl(
|
97
|
+
execute_prlctl('set', @uuid, *args)
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
@@ -127,7 +127,7 @@ module VagrantPlugins
|
|
127
127
|
|
128
128
|
def read_host_only_interfaces
|
129
129
|
net_list = read_virtual_networks
|
130
|
-
net_list.keep_if { |net| net['Type'] ==
|
130
|
+
net_list.keep_if { |net| net['Type'] == 'host-only' }
|
131
131
|
|
132
132
|
hostonly_ifaces = []
|
133
133
|
net_list.each do |iface|
|
@@ -142,7 +142,7 @@ module VagrantPlugins
|
|
142
142
|
info[:netmask] = adapter['Subnet mask'] || adapter['IPv4 subnet mask']
|
143
143
|
|
144
144
|
# Such interfaces are always in 'Up'
|
145
|
-
info[:status] =
|
145
|
+
info[:status] = 'Up'
|
146
146
|
|
147
147
|
# There may be a fake DHCPv4 parameters
|
148
148
|
# We can trust them only if adapter IP and DHCP IP are in the same subnet
|
@@ -165,18 +165,18 @@ module VagrantPlugins
|
|
165
165
|
|
166
166
|
# Get enabled VM's network interfaces
|
167
167
|
ifaces = read_settings.fetch('Hardware', {}).keep_if do |dev, params|
|
168
|
-
dev.start_with?('net') and params.fetch(
|
168
|
+
dev.start_with?('net') and params.fetch('enabled', true)
|
169
169
|
end
|
170
170
|
ifaces.each do |name, params|
|
171
171
|
adapter = name.match(/^net(\d+)$/)[1].to_i
|
172
172
|
nics[adapter] ||= {}
|
173
173
|
|
174
|
-
if params['type'] ==
|
174
|
+
if params['type'] == 'shared'
|
175
175
|
nics[adapter][:type] = :shared
|
176
|
-
elsif params['type'] ==
|
176
|
+
elsif params['type'] == 'host'
|
177
177
|
nics[adapter][:type] = :hostonly
|
178
178
|
nics[adapter][:hostonly] = params.fetch('iface','')
|
179
|
-
elsif params['type'] ==
|
179
|
+
elsif params['type'] == 'bridged'
|
180
180
|
nics[adapter][:type] = :bridged
|
181
181
|
nics[adapter][:bridge] = params.fetch('iface','')
|
182
182
|
end
|
@@ -227,12 +227,6 @@ module VagrantPlugins
|
|
227
227
|
# Ignore our own used ports
|
228
228
|
read_forwarded_ports(true).reject { |r| r[:guest].include?(@uuid) }
|
229
229
|
end
|
230
|
-
|
231
|
-
def set_power_consumption_mode(optimized)
|
232
|
-
state = optimized ? 'on' : 'off'
|
233
|
-
execute_prlctl('set', @uuid, '--longer-battery-life', state)
|
234
|
-
end
|
235
|
-
|
236
230
|
end
|
237
231
|
end
|
238
232
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
|
3
|
+
require 'vagrant/util/platform'
|
4
|
+
|
5
|
+
require File.expand_path('../pd_10', __FILE__)
|
6
|
+
|
7
|
+
module VagrantPlugins
|
8
|
+
module Parallels
|
9
|
+
module Driver
|
10
|
+
# Driver for Parallels Desktop 11.
|
11
|
+
class PD_11 < PD_10
|
12
|
+
def initialize(uuid)
|
13
|
+
super(uuid)
|
14
|
+
|
15
|
+
@logger = Log4r::Logger.new('vagrant_parallels::driver::pd_11')
|
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
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -12,69 +12,9 @@ module VagrantPlugins
|
|
12
12
|
# Driver for Parallels Desktop 8.
|
13
13
|
class PD_8 < Base
|
14
14
|
def initialize(uuid)
|
15
|
-
super()
|
15
|
+
super(uuid)
|
16
16
|
|
17
17
|
@logger = Log4r::Logger.new('vagrant_parallels::driver::pd_8')
|
18
|
-
@uuid = uuid
|
19
|
-
end
|
20
|
-
|
21
|
-
|
22
|
-
def compact(uuid)
|
23
|
-
used_drives = read_settings.fetch('Hardware', {}).select do |name, _|
|
24
|
-
name.start_with? 'hdd'
|
25
|
-
end
|
26
|
-
used_drives.each_value do |drive_params|
|
27
|
-
execute(@prldisktool_path, 'compact', '--hdd', drive_params['image']) do |type, data|
|
28
|
-
lines = data.split("\r")
|
29
|
-
# The progress of the compact will be in the last line. Do a greedy
|
30
|
-
# regular expression to find what we're looking for.
|
31
|
-
if lines.last =~ /.+?(\d{,3}) ?%/
|
32
|
-
yield $1.to_i if block_given?
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def clear_shared_folders
|
39
|
-
share_ids = read_shared_folders.keys
|
40
|
-
share_ids.each do |id|
|
41
|
-
execute_prlctl('set', @uuid, '--shf-host-del', id)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def create_host_only_network(options)
|
46
|
-
# Create the interface
|
47
|
-
execute_prlsrvctl('net', 'add', options[:network_id], '--type', 'host-only')
|
48
|
-
|
49
|
-
# Configure it
|
50
|
-
args = ["--ip", "#{options[:adapter_ip]}/#{options[:netmask]}"]
|
51
|
-
if options[:dhcp]
|
52
|
-
args.concat(["--dhcp-ip", options[:dhcp][:ip],
|
53
|
-
"--ip-scope-start", options[:dhcp][:lower],
|
54
|
-
"--ip-scope-end", options[:dhcp][:upper]])
|
55
|
-
end
|
56
|
-
|
57
|
-
execute_prlsrvctl('net', 'set', options[:network_id], *args)
|
58
|
-
|
59
|
-
# Return the details
|
60
|
-
{
|
61
|
-
name: options[:network_id],
|
62
|
-
ip: options[:adapter_ip],
|
63
|
-
netmask: options[:netmask],
|
64
|
-
dhcp: options[:dhcp]
|
65
|
-
}
|
66
|
-
end
|
67
|
-
|
68
|
-
def delete
|
69
|
-
execute_prlctl('delete', @uuid)
|
70
|
-
end
|
71
|
-
|
72
|
-
def delete_disabled_adapters
|
73
|
-
read_settings.fetch('Hardware', {}).each do |adapter, params|
|
74
|
-
if adapter.start_with?('net') and !params.fetch('enabled', true)
|
75
|
-
execute_prlctl('set', @uuid, '--device-del', adapter)
|
76
|
-
end
|
77
|
-
end
|
78
18
|
end
|
79
19
|
|
80
20
|
def delete_unused_host_only_networks
|
@@ -152,124 +92,6 @@ module VagrantPlugins
|
|
152
92
|
end
|
153
93
|
end
|
154
94
|
|
155
|
-
def export(path, tpl_name)
|
156
|
-
execute_prlctl('clone', @uuid,
|
157
|
-
'--name', tpl_name,
|
158
|
-
'--template',
|
159
|
-
'--dst', path.to_s) do |type, data|
|
160
|
-
lines = data.split("\r")
|
161
|
-
# The progress of the export will be in the last line. Do a greedy
|
162
|
-
# regular expression to find what we're looking for.
|
163
|
-
if lines.last =~ /.+?(\d{,3}) ?%/
|
164
|
-
yield $1.to_i if block_given?
|
165
|
-
end
|
166
|
-
end
|
167
|
-
read_vms[tpl_name]
|
168
|
-
end
|
169
|
-
|
170
|
-
def halt(force=false)
|
171
|
-
args = ['stop', @uuid]
|
172
|
-
args << '--kill' if force
|
173
|
-
execute_prlctl(*args)
|
174
|
-
end
|
175
|
-
|
176
|
-
def import(tpl_name)
|
177
|
-
vm_name = "#{tpl_name}_#{(Time.now.to_f * 1000.0).to_i}_#{rand(100000)}"
|
178
|
-
|
179
|
-
execute_prlctl('clone', tpl_name, '--name', vm_name) do |type, data|
|
180
|
-
lines = data.split("\r")
|
181
|
-
# The progress of the import will be in the last line. Do a greedy
|
182
|
-
# regular expression to find what we're looking for.
|
183
|
-
if lines.last =~ /.+?(\d{,3}) ?%/
|
184
|
-
yield $1.to_i if block_given?
|
185
|
-
end
|
186
|
-
end
|
187
|
-
read_vms[vm_name]
|
188
|
-
end
|
189
|
-
|
190
|
-
def read_bridged_interfaces
|
191
|
-
host_hw_info = read_host_info.fetch("Hardware info")
|
192
|
-
net_list = host_hw_info.select do |name, attrs|
|
193
|
-
# Get all network interfaces except 'vnicXXX'
|
194
|
-
attrs.fetch("type") == "net" and name !~ /^(vnic(.+?))$/
|
195
|
-
end
|
196
|
-
|
197
|
-
bridged_ifaces = []
|
198
|
-
net_list.keys.each do |iface|
|
199
|
-
info = {}
|
200
|
-
ifconfig = execute('ifconfig', iface)
|
201
|
-
# Assign default values
|
202
|
-
info[:name] = iface
|
203
|
-
info[:ip] = "0.0.0.0"
|
204
|
-
info[:netmask] = "0.0.0.0"
|
205
|
-
info[:status] = "Down"
|
206
|
-
|
207
|
-
if ifconfig =~ /(?<=inet\s)(\S*)/
|
208
|
-
info[:ip] = $1.to_s
|
209
|
-
end
|
210
|
-
if ifconfig =~ /(?<=netmask\s)(\S*)/
|
211
|
-
# Netmask will be converted from hex to dec:
|
212
|
-
# '0xffffff00' -> '255.255.255.0'
|
213
|
-
info[:netmask] = $1.hex.to_s(16).scan(/../).each.map{|octet| octet.hex}.join(".")
|
214
|
-
end
|
215
|
-
if ifconfig =~ /\W(UP)\W/ and ifconfig !~ /(?<=status:\s)inactive$/
|
216
|
-
info[:status] = "Up"
|
217
|
-
end
|
218
|
-
|
219
|
-
bridged_ifaces << info
|
220
|
-
end
|
221
|
-
bridged_ifaces
|
222
|
-
end
|
223
|
-
|
224
|
-
def read_guest_ip
|
225
|
-
mac_addr = read_mac_address.downcase
|
226
|
-
leases_file = "/Library/Preferences/Parallels/parallels_dhcp_leases"
|
227
|
-
begin
|
228
|
-
File.open(leases_file).grep(/#{mac_addr}/) do |line|
|
229
|
-
return line[/^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/]
|
230
|
-
end
|
231
|
-
rescue Errno::EACCES
|
232
|
-
raise Errors::DhcpLeasesNotAccessible, :leases_file => leases_file.to_s
|
233
|
-
rescue Errno::ENOENT
|
234
|
-
# File does not exist
|
235
|
-
# Perhaps, it is the fist start of Parallels Desktop
|
236
|
-
return nil
|
237
|
-
end
|
238
|
-
|
239
|
-
nil
|
240
|
-
end
|
241
|
-
|
242
|
-
def read_guest_tools_iso_path(guest_os)
|
243
|
-
guest_os = guest_os.to_sym
|
244
|
-
iso_name ={
|
245
|
-
linux: "prl-tools-lin.iso",
|
246
|
-
darwin: "prl-tools-mac.iso",
|
247
|
-
windows: "prl-tools-win.iso"
|
248
|
-
}
|
249
|
-
return nil if !iso_name[guest_os]
|
250
|
-
|
251
|
-
bundle_id = 'com.parallels.desktop.console'
|
252
|
-
bundle_path = execute('mdfind', "kMDItemCFBundleIdentifier == #{bundle_id}")
|
253
|
-
iso_path = File.expand_path("./Contents/Resources/Tools/#{iso_name[guest_os]}",
|
254
|
-
bundle_path.split("\n")[0])
|
255
|
-
|
256
|
-
if !File.exist?(iso_path)
|
257
|
-
raise Errors::ParallelsToolsIsoNotFound, :iso_path => iso_path
|
258
|
-
end
|
259
|
-
|
260
|
-
iso_path
|
261
|
-
end
|
262
|
-
|
263
|
-
def read_guest_tools_state
|
264
|
-
state = read_settings.fetch('GuestTools', {}).fetch('state', nil)
|
265
|
-
state = "not_installed" if !state
|
266
|
-
state.to_sym
|
267
|
-
end
|
268
|
-
|
269
|
-
def read_host_info
|
270
|
-
json { execute_prlctl('server', 'info', '--json') }
|
271
|
-
end
|
272
|
-
|
273
95
|
def read_host_only_interfaces
|
274
96
|
net_list = read_virtual_networks
|
275
97
|
net_list.keep_if { |net| net['Type'] == "host-only" }
|
@@ -301,23 +123,6 @@ module VagrantPlugins
|
|
301
123
|
hostonly_ifaces
|
302
124
|
end
|
303
125
|
|
304
|
-
def read_mac_address
|
305
|
-
hw_info = read_settings.fetch('Hardware', {})
|
306
|
-
shared_ifaces = hw_info.select do |name, params|
|
307
|
-
name.start_with?('net') && params['type'] == 'shared'
|
308
|
-
end
|
309
|
-
|
310
|
-
if shared_ifaces.empty?
|
311
|
-
raise Errors::SharedAdapterNotFound
|
312
|
-
end
|
313
|
-
|
314
|
-
shared_ifaces.values.first.fetch('mac', nil)
|
315
|
-
end
|
316
|
-
|
317
|
-
def read_mac_addresses
|
318
|
-
read_vm_option('mac').strip.gsub(':', '').split(' ')
|
319
|
-
end
|
320
|
-
|
321
126
|
def read_network_interfaces
|
322
127
|
nics = {}
|
323
128
|
|
@@ -347,19 +152,6 @@ module VagrantPlugins
|
|
347
152
|
nics
|
348
153
|
end
|
349
154
|
|
350
|
-
def read_settings
|
351
|
-
vm = json { execute_prlctl('list', @uuid, '--info', '--no-header', '--json') }
|
352
|
-
vm.last
|
353
|
-
end
|
354
|
-
|
355
|
-
def read_shared_network_id
|
356
|
-
# There should be only one Shared interface
|
357
|
-
shared_net = read_virtual_networks.detect do |net|
|
358
|
-
net['Type'] == 'shared'
|
359
|
-
end
|
360
|
-
shared_net.fetch('Network ID')
|
361
|
-
end
|
362
|
-
|
363
155
|
def read_shared_interface
|
364
156
|
net_info = json do
|
365
157
|
execute_prlsrvctl('net', 'info', read_shared_network_id, '--json')
|
@@ -381,194 +173,6 @@ module VagrantPlugins
|
|
381
173
|
|
382
174
|
info
|
383
175
|
end
|
384
|
-
|
385
|
-
def read_shared_folders
|
386
|
-
shf_info = read_settings.fetch("Host Shared Folders", {})
|
387
|
-
list = {}
|
388
|
-
shf_info.delete_if {|k,v| k == "enabled"}.each do |id, data|
|
389
|
-
list[id] = data.fetch("path")
|
390
|
-
end
|
391
|
-
|
392
|
-
list
|
393
|
-
end
|
394
|
-
|
395
|
-
def read_state
|
396
|
-
read_vm_option('status').strip.to_sym
|
397
|
-
end
|
398
|
-
|
399
|
-
def read_virtual_networks
|
400
|
-
json { execute_prlsrvctl('net', 'list', '--json') }
|
401
|
-
end
|
402
|
-
|
403
|
-
def read_vm_option(option, uuid=@uuid)
|
404
|
-
out = execute_prlctl('list', uuid,'--no-header', '-o', option).strip
|
405
|
-
if out.empty?
|
406
|
-
raise Errors::ParallelsVMOptionNotFound, vm_option: option
|
407
|
-
end
|
408
|
-
|
409
|
-
out
|
410
|
-
end
|
411
|
-
|
412
|
-
def read_vms
|
413
|
-
args = %w(list --all --no-header --json -o name,uuid)
|
414
|
-
vms_arr = json([]) { execute_prlctl(*args) }
|
415
|
-
templates_arr = json([]) { execute_prlctl(*args, '--template') }
|
416
|
-
|
417
|
-
vms = vms_arr | templates_arr
|
418
|
-
Hash[vms.map { |i| [i.fetch('name'), i.fetch('uuid')] }]
|
419
|
-
end
|
420
|
-
|
421
|
-
# Parse the JSON from *all* VMs and templates.
|
422
|
-
# Then return an array of objects (without duplicates)
|
423
|
-
def read_vms_info
|
424
|
-
args = %w(list --all --info --no-header --json)
|
425
|
-
vms_arr = json([]) { execute_prlctl(*args) }
|
426
|
-
templates_arr = json([]) { execute_prlctl(*args, '--template') }
|
427
|
-
|
428
|
-
vms_arr | templates_arr
|
429
|
-
end
|
430
|
-
|
431
|
-
def read_vms_paths
|
432
|
-
list = {}
|
433
|
-
read_vms_info.each do |item|
|
434
|
-
if Dir.exists? item.fetch('Home')
|
435
|
-
list[File.realpath item.fetch('Home')] = item.fetch('ID')
|
436
|
-
end
|
437
|
-
end
|
438
|
-
|
439
|
-
list
|
440
|
-
end
|
441
|
-
|
442
|
-
def regenerate_src_uuid
|
443
|
-
settings = read_settings
|
444
|
-
vm_config = File.join(settings.fetch('Home'), 'config.pvs')
|
445
|
-
|
446
|
-
# Generate and put new SourceVmUuid
|
447
|
-
xml = Nokogiri::XML(File.open(vm_config))
|
448
|
-
p = '//ParallelsVirtualMachine/Identification/SourceVmUuid'
|
449
|
-
xml.xpath(p).first.content = "{#{SecureRandom.uuid}}"
|
450
|
-
|
451
|
-
File.open(vm_config, 'w') do |f|
|
452
|
-
f.write xml.to_xml
|
453
|
-
end
|
454
|
-
end
|
455
|
-
|
456
|
-
def register(pvm_file)
|
457
|
-
args = [@prlctl_path, 'register', pvm_file]
|
458
|
-
|
459
|
-
3.times do
|
460
|
-
result = raw(*args)
|
461
|
-
# Exit if everything is OK
|
462
|
-
return if result.exit_code == 0
|
463
|
-
|
464
|
-
# It may occur in the race condition with other Vagrant processes.
|
465
|
-
# It is OK, just exit.
|
466
|
-
return if result.stderr.include?('is already registered.')
|
467
|
-
|
468
|
-
# Sleep a bit though to give Parallels Desktop time to fix itself
|
469
|
-
sleep 2
|
470
|
-
end
|
471
|
-
|
472
|
-
# If we reach this point, it means that we consistently got the
|
473
|
-
# failure, do a standard execute now. This will raise an
|
474
|
-
# exception if it fails again.
|
475
|
-
execute(*args)
|
476
|
-
end
|
477
|
-
|
478
|
-
def registered?(uuid)
|
479
|
-
args = %w(list --all --info --no-header -o uuid)
|
480
|
-
|
481
|
-
execute_prlctl(*args).include?(uuid) ||
|
482
|
-
execute_prlctl(*args, '--template').include?(uuid)
|
483
|
-
end
|
484
|
-
|
485
|
-
def resume
|
486
|
-
execute_prlctl('resume', @uuid)
|
487
|
-
end
|
488
|
-
|
489
|
-
def set_mac_address(mac)
|
490
|
-
execute_prlctl('set', @uuid,
|
491
|
-
'--device-set', 'net0',
|
492
|
-
'--type', 'shared',
|
493
|
-
'--mac', mac)
|
494
|
-
end
|
495
|
-
|
496
|
-
def set_name(name)
|
497
|
-
execute_prlctl('set', @uuid, '--name', name)
|
498
|
-
end
|
499
|
-
|
500
|
-
def share_folders(folders)
|
501
|
-
folders.each do |folder|
|
502
|
-
# Add the shared folder
|
503
|
-
execute_prlctl('set', @uuid,
|
504
|
-
'--shf-host-add', folder[:name],
|
505
|
-
'--path', folder[:hostpath])
|
506
|
-
end
|
507
|
-
end
|
508
|
-
|
509
|
-
def ssh_ip
|
510
|
-
read_guest_ip
|
511
|
-
end
|
512
|
-
|
513
|
-
def ssh_port(expected_port)
|
514
|
-
expected_port
|
515
|
-
end
|
516
|
-
|
517
|
-
def start
|
518
|
-
execute_prlctl('start', @uuid)
|
519
|
-
end
|
520
|
-
|
521
|
-
def suspend
|
522
|
-
execute_prlctl('suspend', @uuid)
|
523
|
-
end
|
524
|
-
|
525
|
-
def unregister(uuid)
|
526
|
-
args = [@prlctl_path, 'unregister', uuid]
|
527
|
-
3.times do
|
528
|
-
result = raw(*args)
|
529
|
-
# Exit if everything is OK
|
530
|
-
return if result.exit_code == 0
|
531
|
-
|
532
|
-
# It may occur in the race condition with other Vagrant processes.
|
533
|
-
# Both are OK, just exit.
|
534
|
-
return if result.stderr.include?('is not registered')
|
535
|
-
return if result.stderr.include?('is being cloned')
|
536
|
-
|
537
|
-
# Sleep a bit though to give Parallels Desktop time to fix itself
|
538
|
-
sleep 2
|
539
|
-
end
|
540
|
-
|
541
|
-
# If we reach this point, it means that we consistently got the
|
542
|
-
# failure, do a standard execute now. This will raise an
|
543
|
-
# exception if it fails again.
|
544
|
-
execute(*args)
|
545
|
-
end
|
546
|
-
|
547
|
-
def unshare_folders(names)
|
548
|
-
names.each do |name|
|
549
|
-
execute_prlctl('set', @uuid, '--shf-host-del', name)
|
550
|
-
end
|
551
|
-
end
|
552
|
-
|
553
|
-
def vm_exists?(uuid)
|
554
|
-
5.times do |i|
|
555
|
-
result = raw(@prlctl_path, 'list', uuid)
|
556
|
-
return true if result.exit_code == 0
|
557
|
-
|
558
|
-
# Sometimes this happens. In this case, retry. If
|
559
|
-
# we don't see this text, the VM really probably doesn't exist.
|
560
|
-
return false if !result.stderr.include?('Login failed:')
|
561
|
-
|
562
|
-
# Sleep a bit though to give Parallels Desktop time to fix itself
|
563
|
-
sleep 2
|
564
|
-
end
|
565
|
-
|
566
|
-
# If we reach this point, it means that we consistently got the
|
567
|
-
# failure, do a standard prlctl now. This will raise an
|
568
|
-
# exception if it fails again.
|
569
|
-
execute_prlctl('list', uuid)
|
570
|
-
true
|
571
|
-
end
|
572
176
|
end
|
573
177
|
end
|
574
178
|
end
|
@@ -59,6 +59,10 @@ module VagrantPlugins
|
|
59
59
|
error_key(:shared_adapter_not_found)
|
60
60
|
end
|
61
61
|
|
62
|
+
class SnapshotIdNotDetected < VagrantParallelsError
|
63
|
+
error_key(:snapshot_id_not_detected)
|
64
|
+
end
|
65
|
+
|
62
66
|
class VMImportFailure < VagrantParallelsError
|
63
67
|
error_key(:vm_import_failure)
|
64
68
|
end
|
@@ -91,6 +91,7 @@ module VagrantPlugins
|
|
91
91
|
autoload :PD_8, File.expand_path("../driver/pd_8", __FILE__)
|
92
92
|
autoload :PD_9, File.expand_path("../driver/pd_9", __FILE__)
|
93
93
|
autoload :PD_10, File.expand_path("../driver/pd_10", __FILE__)
|
94
|
+
autoload :PD_11, File.expand_path("../driver/pd_11", __FILE__)
|
94
95
|
end
|
95
96
|
|
96
97
|
module Model
|