vagrant-parallels 1.0.5 → 1.0.6.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/lib/vagrant-parallels/action.rb +0 -2
- data/lib/vagrant-parallels/driver/pd_9.rb +3 -401
- data/lib/vagrant-parallels/guest_cap/linux/mount_parallels_shared_folder.rb +20 -59
- data/lib/vagrant-parallels/version.rb +1 -1
- metadata +2 -3
- data/lib/vagrant-parallels/action/force_prl_fs_mount.rb +0 -55
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c81c8a8004ab4f04103fe026fe8336bceb20087d
|
4
|
+
data.tar.gz: 7c35af159575f21dc35bea6d6b975ebb7e3449c8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 761ef849dd461d789b1826e347c4e42278123995083a5bea95b88f05cf7a11ec1c62b5ee3cce359ee193769bbed5cf4f01e86bd7448d43dfc9a117425d0c7eac
|
7
|
+
data.tar.gz: 658d8e9a2b6eebff58b9b343ebfedf33df44bbf6644ace802068c89668122826077e691b5bf6df811be0aabed5dc9fdbb294bdf37086972d5e5b1f6af9f170cf
|
@@ -168,7 +168,6 @@ module VagrantPlugins
|
|
168
168
|
b2.use EnvSet, :port_collision_repair => false
|
169
169
|
b2.use Resume
|
170
170
|
b2.use WaitForCommunicator, [:resuming, :running]
|
171
|
-
b2.use ForcePrlFsMount
|
172
171
|
else
|
173
172
|
b2.use MessageNotCreated
|
174
173
|
end
|
@@ -284,7 +283,6 @@ module VagrantPlugins
|
|
284
283
|
autoload :DestroyUnusedNetworkInterfaces, File.expand_path("../action/destroy_unused_network_interfaces", __FILE__)
|
285
284
|
autoload :Export, File.expand_path("../action/export", __FILE__)
|
286
285
|
autoload :ForcedHalt, File.expand_path("../action/forced_halt", __FILE__)
|
287
|
-
autoload :ForcePrlFsMount, File.expand_path("../action/force_prl_fs_mount", __FILE__)
|
288
286
|
autoload :Import, File.expand_path("../action/import", __FILE__)
|
289
287
|
autoload :IsSuspended, File.expand_path("../action/is_suspended", __FILE__)
|
290
288
|
autoload :IsRunning, File.expand_path("../action/is_running", __FILE__)
|
@@ -2,307 +2,17 @@ require 'log4r'
|
|
2
2
|
|
3
3
|
require 'vagrant/util/platform'
|
4
4
|
|
5
|
-
require File.expand_path("../
|
5
|
+
require File.expand_path("../pd_8", __FILE__)
|
6
6
|
|
7
7
|
module VagrantPlugins
|
8
8
|
module Parallels
|
9
9
|
module Driver
|
10
10
|
# Driver for Parallels Desktop 9.
|
11
|
-
class PD_9 <
|
11
|
+
class PD_9 < PD_8
|
12
12
|
def initialize(uuid)
|
13
|
-
super()
|
13
|
+
super(uuid)
|
14
14
|
|
15
15
|
@logger = Log4r::Logger.new("vagrant::provider::parallels::pd_9")
|
16
|
-
@uuid = uuid
|
17
|
-
end
|
18
|
-
|
19
|
-
|
20
|
-
def compact(uuid)
|
21
|
-
used_drives = read_settings.fetch('Hardware', {}).select { |name, _| name.start_with? 'hdd' }
|
22
|
-
used_drives.each_value do |drive_params|
|
23
|
-
execute(:prl_disk_tool, 'compact', '--hdd', drive_params["image"]) do |type, data|
|
24
|
-
lines = data.split("\r")
|
25
|
-
# The progress of the compact will be in the last line. Do a greedy
|
26
|
-
# regular expression to find what we're looking for.
|
27
|
-
if lines.last =~ /.+?(\d{,3}) ?%/
|
28
|
-
yield $1.to_i if block_given?
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def clear_shared_folders
|
35
|
-
share_ids = read_shared_folders.keys
|
36
|
-
share_ids.each do |id|
|
37
|
-
execute("set", @uuid, "--shf-host-del", id)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def create_host_only_network(options)
|
42
|
-
# Create the interface
|
43
|
-
execute(:prlsrvctl, "net", "add", options[:network_id], "--type", "host-only")
|
44
|
-
|
45
|
-
# Configure it
|
46
|
-
args = ["--ip", "#{options[:adapter_ip]}/#{options[:netmask]}"]
|
47
|
-
if options[:dhcp]
|
48
|
-
args.concat(["--dhcp-ip", options[:dhcp][:ip],
|
49
|
-
"--ip-scope-start", options[:dhcp][:lower],
|
50
|
-
"--ip-scope-end", options[:dhcp][:upper]])
|
51
|
-
end
|
52
|
-
|
53
|
-
execute(:prlsrvctl, "net", "set", options[:network_id], *args)
|
54
|
-
|
55
|
-
# Determine interface to which it has been bound
|
56
|
-
net_info = json { execute(:prlsrvctl, 'net', 'info', options[:network_id], '--json', retryable: true) }
|
57
|
-
iface_name = net_info['Bound To']
|
58
|
-
|
59
|
-
# Return the details
|
60
|
-
return {
|
61
|
-
:name => iface_name,
|
62
|
-
:ip => options[:adapter_ip],
|
63
|
-
:netmask => options[:netmask],
|
64
|
-
:dhcp => options[:dhcp]
|
65
|
-
}
|
66
|
-
end
|
67
|
-
|
68
|
-
def delete
|
69
|
-
execute('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('set', @uuid, '--device-del', adapter)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def delete_unused_host_only_networks
|
81
|
-
networks = read_virtual_networks
|
82
|
-
|
83
|
-
# 'Shared'(vnic0) and 'Host-Only'(vnic1) are default in Parallels Desktop
|
84
|
-
# They should not be deleted anyway.
|
85
|
-
networks.keep_if do |net|
|
86
|
-
net['Type'] == "host-only" &&
|
87
|
-
net['Bound To'].match(/^(?>vnic|Parallels Host-Only #)(\d+)$/)[1].to_i >= 2
|
88
|
-
end
|
89
|
-
|
90
|
-
read_vms_info.each do |vm|
|
91
|
-
used_nets = vm.fetch('Hardware', {}).select { |name, _| name.start_with? 'net' }
|
92
|
-
used_nets.each_value do |net_params|
|
93
|
-
networks.delete_if { |net| net['Bound To'] == net_params.fetch('iface', nil) }
|
94
|
-
end
|
95
|
-
|
96
|
-
end
|
97
|
-
|
98
|
-
networks.each do |net|
|
99
|
-
# Delete the actual host only network interface.
|
100
|
-
execute(:prlsrvctl, "net", "del", net["Network ID"])
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
def enable_adapters(adapters)
|
105
|
-
# Get adapters which have already configured for this VM
|
106
|
-
# Such adapters will be just overridden
|
107
|
-
existing_adapters = read_settings.fetch('Hardware', {}).keys.select { |name| name.start_with? 'net' }
|
108
|
-
|
109
|
-
# Disable all previously existing adapters (except shared 'vnet0')
|
110
|
-
existing_adapters.each do |adapter|
|
111
|
-
if adapter != 'vnet0'
|
112
|
-
execute('set', @uuid, '--device-set', adapter, '--disable')
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
adapters.each do |adapter|
|
117
|
-
args = []
|
118
|
-
if existing_adapters.include? "net#{adapter[:adapter]}"
|
119
|
-
args.concat(["--device-set","net#{adapter[:adapter]}", "--enable"])
|
120
|
-
else
|
121
|
-
args.concat(["--device-add", "net"])
|
122
|
-
end
|
123
|
-
|
124
|
-
if adapter[:type] == :hostonly
|
125
|
-
# Oddly enough, but there is a 'bridge' anyway.
|
126
|
-
# The only difference is the destination interface:
|
127
|
-
# - in host-only (private) network it will be bridged to the 'vnicX' device
|
128
|
-
# - in real bridge (public) network it will be bridged to the assigned device
|
129
|
-
args.concat(["--type", "bridged", "--iface", adapter[:hostonly]])
|
130
|
-
elsif adapter[:type] == :bridge
|
131
|
-
args.concat(["--type", "bridged", "--iface", adapter[:bridge]])
|
132
|
-
elsif adapter[:type] == :shared
|
133
|
-
args.concat(["--type", "shared"])
|
134
|
-
end
|
135
|
-
|
136
|
-
if adapter[:mac_address]
|
137
|
-
args.concat(["--mac", adapter[:mac_address]])
|
138
|
-
end
|
139
|
-
|
140
|
-
if adapter[:nic_type]
|
141
|
-
args.concat(["--adapter-type", adapter[:nic_type].to_s])
|
142
|
-
end
|
143
|
-
|
144
|
-
execute("set", @uuid, *args)
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
def execute_command(command)
|
149
|
-
execute(*command)
|
150
|
-
end
|
151
|
-
|
152
|
-
def export(path, tpl_name)
|
153
|
-
execute("clone", @uuid, "--name", tpl_name, "--template", "--dst", path.to_s) do |type, data|
|
154
|
-
lines = data.split("\r")
|
155
|
-
# The progress of the export will be in the last line. Do a greedy
|
156
|
-
# regular expression to find what we're looking for.
|
157
|
-
if lines.last =~ /.+?(\d{,3}) ?%/
|
158
|
-
yield $1.to_i if block_given?
|
159
|
-
end
|
160
|
-
end
|
161
|
-
read_vms[tpl_name]
|
162
|
-
end
|
163
|
-
|
164
|
-
def halt(force=false)
|
165
|
-
args = ['stop', @uuid]
|
166
|
-
args << '--kill' if force
|
167
|
-
execute(*args)
|
168
|
-
end
|
169
|
-
|
170
|
-
def import(template_uuid)
|
171
|
-
template_name = read_vms.key(template_uuid)
|
172
|
-
vm_name = "#{template_name}_#{(Time.now.to_f * 1000.0).to_i}_#{rand(100000)}"
|
173
|
-
|
174
|
-
execute("clone", template_uuid, '--name', vm_name) do |type, data|
|
175
|
-
lines = data.split("\r")
|
176
|
-
# The progress of the import will be in the last line. Do a greedy
|
177
|
-
# regular expression to find what we're looking for.
|
178
|
-
if lines.last =~ /.+?(\d{,3}) ?%/
|
179
|
-
yield $1.to_i if block_given?
|
180
|
-
end
|
181
|
-
end
|
182
|
-
read_vms[vm_name]
|
183
|
-
end
|
184
|
-
|
185
|
-
def read_bridged_interfaces
|
186
|
-
host_hw_info = read_host_info.fetch("Hardware info")
|
187
|
-
net_list = host_hw_info.select do |name, attrs|
|
188
|
-
# Get all network interfaces except 'vnicXXX'
|
189
|
-
attrs.fetch("type") == "net" and name !~ /^(vnic(.+?))$/
|
190
|
-
end
|
191
|
-
|
192
|
-
bridged_ifaces = []
|
193
|
-
net_list.keys.each do |iface|
|
194
|
-
info = {}
|
195
|
-
ifconfig = execute(:ifconfig, iface)
|
196
|
-
# Assign default values
|
197
|
-
info[:name] = iface
|
198
|
-
info[:ip] = "0.0.0.0"
|
199
|
-
info[:netmask] = "0.0.0.0"
|
200
|
-
info[:status] = "Down"
|
201
|
-
|
202
|
-
if ifconfig =~ /(?<=inet\s)(\S*)/
|
203
|
-
info[:ip] = $1.to_s
|
204
|
-
end
|
205
|
-
if ifconfig =~ /(?<=netmask\s)(\S*)/
|
206
|
-
# Netmask will be converted from hex to dec:
|
207
|
-
# '0xffffff00' -> '255.255.255.0'
|
208
|
-
info[:netmask] = $1.hex.to_s(16).scan(/../).each.map{|octet| octet.hex}.join(".")
|
209
|
-
end
|
210
|
-
if ifconfig =~ /\W(UP)\W/ and ifconfig !~ /(?<=status:\s)inactive$/
|
211
|
-
info[:status] = "Up"
|
212
|
-
end
|
213
|
-
|
214
|
-
bridged_ifaces << info
|
215
|
-
end
|
216
|
-
bridged_ifaces
|
217
|
-
end
|
218
|
-
|
219
|
-
def read_guest_ip
|
220
|
-
mac_addr = read_mac_address.downcase
|
221
|
-
leases_file = "/Library/Preferences/Parallels/parallels_dhcp_leases"
|
222
|
-
begin
|
223
|
-
File.open(leases_file).grep(/#{mac_addr}/) do |line|
|
224
|
-
return line[/^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/]
|
225
|
-
end
|
226
|
-
rescue Errno::EACCES
|
227
|
-
raise Errors::DhcpLeasesNotAccessible, :leases_file => leases_file.to_s
|
228
|
-
rescue Errno::ENOENT
|
229
|
-
# File does not exist
|
230
|
-
# Perhaps, it is the fist start of Parallels Desktop
|
231
|
-
return nil
|
232
|
-
end
|
233
|
-
|
234
|
-
nil
|
235
|
-
end
|
236
|
-
|
237
|
-
def read_guest_tools_version
|
238
|
-
read_settings.fetch('GuestTools', {}).fetch('version', nil)
|
239
|
-
end
|
240
|
-
|
241
|
-
def read_host_info
|
242
|
-
json { execute('server', 'info', '--json', retryable: true) }
|
243
|
-
end
|
244
|
-
|
245
|
-
def read_host_only_interfaces
|
246
|
-
net_list = read_virtual_networks
|
247
|
-
net_list.keep_if { |net| net['Type'] == "host-only" }
|
248
|
-
|
249
|
-
hostonly_ifaces = []
|
250
|
-
net_list.each do |iface|
|
251
|
-
info = {}
|
252
|
-
net_info = json { execute(:prlsrvctl, 'net', 'info', iface['Network ID'], '--json') }
|
253
|
-
# Really we need to work with bounded virtual interface
|
254
|
-
info[:name] = net_info['Bound To']
|
255
|
-
info[:ip] = net_info['Parallels adapter']['IP address']
|
256
|
-
info[:netmask] = net_info['Parallels adapter']['Subnet mask']
|
257
|
-
# Such interfaces are always in 'Up'
|
258
|
-
info[:status] = "Up"
|
259
|
-
|
260
|
-
# There may be a fake DHCPv4 parameters
|
261
|
-
# We can trust them only if adapter IP and DHCP IP are in the same subnet
|
262
|
-
dhcp_ip = net_info['DHCPv4 server']['Server address']
|
263
|
-
if network_address(info[:ip], info[:netmask]) == network_address(dhcp_ip, info[:netmask])
|
264
|
-
info[:dhcp] = {
|
265
|
-
:ip => dhcp_ip,
|
266
|
-
:lower => net_info['DHCPv4 server']['IP scope start address'],
|
267
|
-
:upper => net_info['DHCPv4 server']['IP scope end address']
|
268
|
-
}
|
269
|
-
end
|
270
|
-
hostonly_ifaces << info
|
271
|
-
end
|
272
|
-
hostonly_ifaces
|
273
|
-
end
|
274
|
-
|
275
|
-
def read_mac_address
|
276
|
-
read_settings.fetch('Hardware', {}).fetch('net0', {}).fetch('mac', nil)
|
277
|
-
end
|
278
|
-
|
279
|
-
def read_network_interfaces
|
280
|
-
nics = {}
|
281
|
-
|
282
|
-
# Get enabled VM's network interfaces
|
283
|
-
ifaces = read_settings.fetch('Hardware', {}).keep_if do |dev, params|
|
284
|
-
dev.start_with?('net') and params.fetch("enabled", true)
|
285
|
-
end
|
286
|
-
ifaces.each do |name, params|
|
287
|
-
adapter = name.match(/^net(\d+)$/)[1].to_i
|
288
|
-
nics[adapter] ||= {}
|
289
|
-
|
290
|
-
if params['type'] == "shared"
|
291
|
-
nics[adapter][:type] = :shared
|
292
|
-
elsif params['type'] == "host"
|
293
|
-
# It is PD internal host-only network and it is bounded to 'vnic1'
|
294
|
-
nics[adapter][:type] = :hostonly
|
295
|
-
nics[adapter][:hostonly] = "vnic1"
|
296
|
-
elsif params['type'] == "bridged" and params.fetch('iface','').start_with?('vnic')
|
297
|
-
# Bridged to the 'vnicXX'? Then it is a host-only, actually.
|
298
|
-
nics[adapter][:type] = :hostonly
|
299
|
-
nics[adapter][:hostonly] = params.fetch('iface','')
|
300
|
-
elsif params['type'] == "bridged"
|
301
|
-
nics[adapter][:type] = :bridged
|
302
|
-
nics[adapter][:bridge] = params.fetch('iface','')
|
303
|
-
end
|
304
|
-
end
|
305
|
-
nics
|
306
16
|
end
|
307
17
|
|
308
18
|
def read_settings
|
@@ -310,50 +20,12 @@ module VagrantPlugins
|
|
310
20
|
vm.last
|
311
21
|
end
|
312
22
|
|
313
|
-
def read_shared_interface
|
314
|
-
# There should be only one Shared interface
|
315
|
-
shared_net = read_virtual_networks.detect { |net| net['Type'] == 'shared' }
|
316
|
-
return nil if !shared_net
|
317
|
-
|
318
|
-
net_info = json { execute(:prlsrvctl, 'net', 'info', shared_net['Network ID'], '--json') }
|
319
|
-
info = {
|
320
|
-
name: net_info['Bound To'],
|
321
|
-
ip: net_info['Parallels adapter']['IP address'],
|
322
|
-
netmask: net_info['Parallels adapter']['Subnet mask'],
|
323
|
-
status: "Up"
|
324
|
-
}
|
325
|
-
|
326
|
-
if net_info.key?('DHCPv4 server')
|
327
|
-
info[:dhcp] = {
|
328
|
-
ip: net_info['DHCPv4 server']['Server address'],
|
329
|
-
lower: net_info['DHCPv4 server']['IP scope start address'],
|
330
|
-
upper: net_info['DHCPv4 server']['IP scope end address']
|
331
|
-
}
|
332
|
-
end
|
333
|
-
|
334
|
-
info
|
335
|
-
end
|
336
|
-
|
337
|
-
def read_shared_folders
|
338
|
-
shf_info = read_settings.fetch("Host Shared Folders", {})
|
339
|
-
list = {}
|
340
|
-
shf_info.delete_if {|k,v| k == "enabled"}.each do |id, data|
|
341
|
-
list[id] = data.fetch("path")
|
342
|
-
end
|
343
|
-
|
344
|
-
list
|
345
|
-
end
|
346
|
-
|
347
23
|
def read_state
|
348
24
|
vm = json { execute('list', @uuid, '--json', retryable: true) }
|
349
25
|
return nil if !vm.last
|
350
26
|
vm.last.fetch('status').to_sym
|
351
27
|
end
|
352
28
|
|
353
|
-
def read_virtual_networks
|
354
|
-
json { execute(:prlsrvctl, 'net', 'list', '--json', retryable: true) }
|
355
|
-
end
|
356
|
-
|
357
29
|
def read_vms
|
358
30
|
results = {}
|
359
31
|
vms_arr = json([]) do
|
@@ -380,76 +52,6 @@ module VagrantPlugins
|
|
380
52
|
end
|
381
53
|
vms_arr | templates_arr
|
382
54
|
end
|
383
|
-
|
384
|
-
def read_vms_paths
|
385
|
-
list = {}
|
386
|
-
read_vms_info.each do |item|
|
387
|
-
if Dir.exists? item.fetch('Home')
|
388
|
-
list[File.realpath item.fetch('Home')] = item.fetch('ID')
|
389
|
-
end
|
390
|
-
end
|
391
|
-
|
392
|
-
list
|
393
|
-
end
|
394
|
-
|
395
|
-
def register(pvm_file)
|
396
|
-
execute("register", pvm_file)
|
397
|
-
end
|
398
|
-
|
399
|
-
def registered?(uuid)
|
400
|
-
read_vms.has_value?(uuid)
|
401
|
-
end
|
402
|
-
|
403
|
-
def resume
|
404
|
-
execute('resume', @uuid)
|
405
|
-
end
|
406
|
-
|
407
|
-
def set_mac_address(mac)
|
408
|
-
execute('set', @uuid, '--device-set', 'net0', '--type', 'shared', '--mac', mac)
|
409
|
-
end
|
410
|
-
|
411
|
-
def set_name(name)
|
412
|
-
execute('set', @uuid, '--name', name, :retryable => true)
|
413
|
-
end
|
414
|
-
|
415
|
-
def share_folders(folders)
|
416
|
-
folders.each do |folder|
|
417
|
-
# Add the shared folder
|
418
|
-
execute('set', @uuid, '--shf-host-add', folder[:name], '--path', folder[:hostpath])
|
419
|
-
end
|
420
|
-
end
|
421
|
-
|
422
|
-
def ssh_port(expected_port)
|
423
|
-
expected_port
|
424
|
-
end
|
425
|
-
|
426
|
-
def start
|
427
|
-
execute('start', @uuid)
|
428
|
-
end
|
429
|
-
|
430
|
-
def suspend
|
431
|
-
execute('suspend', @uuid)
|
432
|
-
end
|
433
|
-
|
434
|
-
def unregister(uuid)
|
435
|
-
execute("unregister", uuid)
|
436
|
-
end
|
437
|
-
|
438
|
-
def verify!
|
439
|
-
version
|
440
|
-
end
|
441
|
-
|
442
|
-
def version
|
443
|
-
if execute('--version', retryable: true) =~ /prlctl version ([\d\.]+)/
|
444
|
-
$1.downcase
|
445
|
-
else
|
446
|
-
raise VagrantPlugins::Parallels::Errors::ParallelsInstallIncomplete
|
447
|
-
end
|
448
|
-
end
|
449
|
-
|
450
|
-
def vm_exists?(uuid)
|
451
|
-
raw("list", uuid).exit_code == 0
|
452
|
-
end
|
453
55
|
end
|
454
56
|
end
|
455
57
|
end
|
@@ -4,74 +4,35 @@ module VagrantPlugins
|
|
4
4
|
class MountParallelsSharedFolder
|
5
5
|
|
6
6
|
def self.mount_parallels_shared_folder(machine, name, guestpath, options)
|
7
|
+
# Expand the guest path so we can handle things like "~/vagrant"
|
7
8
|
expanded_guest_path = machine.guest.capability(
|
8
9
|
:shell_expand_guest_path, guestpath)
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
else
|
15
|
-
mount_uid = "`id -u #{options[:owner]}`"
|
16
|
-
end
|
17
|
-
|
18
|
-
if options[:group].is_a? Integer
|
19
|
-
mount_gid = options[:group]
|
20
|
-
mount_gid_old = options[:group]
|
21
|
-
else
|
22
|
-
mount_gid = "`getent group #{options[:group]} | cut -d: -f3`"
|
23
|
-
mount_gid_old = "`id -g #{options[:group]}`"
|
24
|
-
end
|
25
|
-
|
26
|
-
# First mount command uses getent to get the group
|
27
|
-
mount_options = "-o uid=#{mount_uid},gid=#{mount_gid}"
|
28
|
-
mount_options += ",#{options[:mount_options].join(",")}" if options[:mount_options]
|
29
|
-
mount_commands << "mount -t prl_fs #{mount_options} #{name} #{expanded_guest_path}"
|
30
|
-
|
31
|
-
# Second mount command uses the old style `id -g`
|
32
|
-
mount_options = "-o uid=#{mount_uid},gid=#{mount_gid_old}"
|
33
|
-
mount_options += ",#{options[:mount_options].join(",")}" if options[:mount_options]
|
34
|
-
mount_commands << "mount -t prl_fs #{mount_options} #{name} #{expanded_guest_path}"
|
35
|
-
|
36
|
-
# Clear prior symlink if exists
|
37
|
-
if machine.communicate.test("test -L #{expanded_guest_path}")
|
38
|
-
machine.communicate.sudo("rm #{expanded_guest_path}")
|
39
|
-
end
|
40
|
-
|
41
|
-
# Create the guest path if it doesn't exist
|
42
|
-
machine.communicate.sudo("mkdir -p #{expanded_guest_path}")
|
43
|
-
|
44
|
-
# Attempt to mount the folder. We retry here a few times because
|
45
|
-
# it can fail early on.
|
46
|
-
attempts = 0
|
47
|
-
while true
|
48
|
-
success = true
|
49
|
-
|
50
|
-
mount_commands.each do |command|
|
51
|
-
no_such_device = false
|
52
|
-
status = machine.communicate.sudo(command, error_check: false) do |type, data|
|
53
|
-
no_such_device = true if type == :stderr && data =~ /No such device/i
|
54
|
-
end
|
55
|
-
|
56
|
-
success = status == 0 && !no_such_device
|
57
|
-
break if success
|
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}\"")
|
58
15
|
end
|
59
16
|
|
60
|
-
|
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
|
61
21
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
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}\"")
|
66
26
|
end
|
67
27
|
|
68
|
-
|
69
|
-
|
28
|
+
# finally make the symlink
|
29
|
+
comm.sudo("ln -s \"/media/psf/#{name}\" \"#{expanded_guest_path}\"")
|
70
30
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
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}")
|
35
|
+
end
|
75
36
|
end
|
76
37
|
end
|
77
38
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vagrant-parallels
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.6.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mikhail Zholobov
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-03-
|
12
|
+
date: 2014-03-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -90,7 +90,6 @@ files:
|
|
90
90
|
- lib/vagrant-parallels/action/destroy.rb
|
91
91
|
- lib/vagrant-parallels/action/destroy_unused_network_interfaces.rb
|
92
92
|
- lib/vagrant-parallels/action/export.rb
|
93
|
-
- lib/vagrant-parallels/action/force_prl_fs_mount.rb
|
94
93
|
- lib/vagrant-parallels/action/forced_halt.rb
|
95
94
|
- lib/vagrant-parallels/action/import.rb
|
96
95
|
- lib/vagrant-parallels/action/is_running.rb
|
@@ -1,55 +0,0 @@
|
|
1
|
-
require "log4r"
|
2
|
-
require 'vagrant/util/platform'
|
3
|
-
|
4
|
-
module VagrantPlugins
|
5
|
-
module Parallels
|
6
|
-
module Action
|
7
|
-
class ForcePrlFsMount
|
8
|
-
# This middleware forces the prl_fs mount after the Resume, because
|
9
|
-
# there is bug in Linux guests - custom shared folders are missed after
|
10
|
-
# the resume [GH-102]
|
11
|
-
include Vagrant::Action::Builtin::MixinSyncedFolders
|
12
|
-
|
13
|
-
def initialize(app, env)
|
14
|
-
@app = app
|
15
|
-
@logger = Log4r::Logger.new("vagrant::plugins::parallels::force_prl_fs_mount")
|
16
|
-
end
|
17
|
-
|
18
|
-
def call(env)
|
19
|
-
# Only for Linux guests!
|
20
|
-
if env[:machine].communicate.test("uname -s | grep 'Linux'")
|
21
|
-
folders = synced_folders(env[:machine])[:parallels]
|
22
|
-
|
23
|
-
# Go through each folder and make sure to create it if
|
24
|
-
# it does not exist on host
|
25
|
-
folders.each do |id, data|
|
26
|
-
data[:hostpath] = File.expand_path(data[:hostpath], env[:root_path])
|
27
|
-
|
28
|
-
# Create the hostpath if it doesn't exist and we've been told to
|
29
|
-
if !File.directory?(data[:hostpath]) && data[:create]
|
30
|
-
@logger.info("Creating shared folder host directory: #{data[:hostpath]}")
|
31
|
-
begin
|
32
|
-
Pathname.new(data[:hostpath]).mkpath
|
33
|
-
rescue Errno::EACCES
|
34
|
-
raise Vagrant::Errors::SharedFolderCreateFailed,
|
35
|
-
path: data[:hostpath]
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
if File.directory?(data[:hostpath])
|
40
|
-
data[:hostpath] = File.realpath(data[:hostpath])
|
41
|
-
data[:hostpath] = Vagrant::Util::Platform.fs_real_path(data[:hostpath]).to_s
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
opts = nil
|
46
|
-
instance = VagrantPlugins::Parallels::SyncedFolder.new
|
47
|
-
instance.enable(env[:machine], folders, opts)
|
48
|
-
end
|
49
|
-
|
50
|
-
@app.call(env)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|