vagrant-parallels 0.2.1 → 0.2.2.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +21 -13
- data/.travis.yml +1 -0
- data/README.md +43 -54
- data/config/i18n-tasks.yml.erb +1 -1
- data/debug.log +941 -0
- data/lib/vagrant-parallels/action.rb +0 -7
- data/lib/vagrant-parallels/action/check_accessible.rb +1 -1
- data/lib/vagrant-parallels/action/check_guest_tools.rb +10 -2
- data/lib/vagrant-parallels/action/clear_network_interfaces.rb +1 -1
- data/lib/vagrant-parallels/action/customize.rb +6 -4
- data/lib/vagrant-parallels/action/export.rb +56 -12
- data/lib/vagrant-parallels/action/import.rb +49 -30
- data/lib/vagrant-parallels/action/network.rb +137 -48
- data/lib/vagrant-parallels/action/package_config_files.rb +0 -12
- data/lib/vagrant-parallels/action/prepare_nfs_valid_ids.rb +1 -1
- data/lib/vagrant-parallels/action/set_name.rb +2 -2
- data/lib/vagrant-parallels/config.rb +11 -2
- data/lib/vagrant-parallels/driver/base.rb +281 -0
- data/lib/vagrant-parallels/driver/meta.rb +138 -0
- data/lib/vagrant-parallels/driver/{prl_ctl.rb → pd_8.rb} +116 -256
- data/lib/vagrant-parallels/driver/pd_9.rb +417 -0
- data/lib/vagrant-parallels/errors.rb +15 -7
- data/lib/vagrant-parallels/plugin.rb +7 -7
- data/lib/vagrant-parallels/provider.rb +33 -3
- data/lib/vagrant-parallels/version.rb +1 -1
- data/locales/en.yml +30 -16
- data/test/unit/base.rb +1 -5
- data/test/unit/config_test.rb +13 -2
- data/test/unit/driver/pd_8_test.rb +196 -0
- data/test/unit/driver/pd_9_test.rb +196 -0
- data/test/unit/locales/locales_test.rb +1 -1
- data/test/unit/support/shared/parallels_context.rb +2 -2
- data/test/unit/support/shared/pd_driver_examples.rb +243 -0
- data/test/unit/synced_folder_test.rb +37 -0
- data/vagrant-parallels.gemspec +5 -5
- metadata +39 -32
- data/lib/vagrant-parallels/action/match_mac_address.rb +0 -28
- data/lib/vagrant-parallels/action/register_template.rb +0 -24
- data/lib/vagrant-parallels/action/unregister_template.rb +0 -26
- data/test/support/isolated_environment.rb +0 -46
- data/test/support/tempdir.rb +0 -43
- data/test/unit/driver/prl_ctl_test.rb +0 -148
@@ -14,21 +14,9 @@ module VagrantPlugins
|
|
14
14
|
def call(env)
|
15
15
|
@env = env
|
16
16
|
create_metadata
|
17
|
-
create_vagrantfile
|
18
17
|
@app.call(env)
|
19
18
|
end
|
20
19
|
|
21
|
-
# This method creates the auto-generated Vagrantfile at the root of the
|
22
|
-
# box. This Vagrantfile contains the MAC address so that the user doesn't
|
23
|
-
# have to worry about it.
|
24
|
-
def create_vagrantfile
|
25
|
-
File.open(File.join(@env["export.temp_dir"], "Vagrantfile"), "w") do |f|
|
26
|
-
f.write(TemplateRenderer.render("package_Vagrantfile", {
|
27
|
-
:base_mac => @env[:machine].provider.driver.read_mac_address
|
28
|
-
}))
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
20
|
def create_metadata
|
33
21
|
File.open(File.join(@env["export.temp_dir"], "metadata.json"), "w") do |f|
|
34
22
|
f.write(template_metadatafile)
|
@@ -28,8 +28,8 @@ module VagrantPlugins
|
|
28
28
|
end
|
29
29
|
|
30
30
|
# Verify the name is not taken
|
31
|
-
vms_names = env[:machine].provider.driver.
|
32
|
-
raise
|
31
|
+
vms_names = env[:machine].provider.driver.read_vms
|
32
|
+
raise VagrantPlugins::Parallels::Errors::VMNameExists, :name => name if \
|
33
33
|
vms_names.has_key?(name) && vms_names[name] != env[:machine].id
|
34
34
|
|
35
35
|
if vms_names.has_key?(name)
|
@@ -1,12 +1,17 @@
|
|
1
1
|
module VagrantPlugins
|
2
2
|
module Parallels
|
3
3
|
class Config < Vagrant.plugin("2", :config)
|
4
|
+
attr_accessor :check_guest_tools
|
4
5
|
attr_reader :customizations
|
5
6
|
attr_accessor :destroy_unused_network_interfaces
|
6
7
|
attr_reader :network_adapters
|
7
8
|
attr_accessor :name
|
8
9
|
|
10
|
+
# Compatibility with virtualbox provider's syntax
|
11
|
+
alias :check_guest_additions= :check_guest_tools=
|
12
|
+
|
9
13
|
def initialize
|
14
|
+
@check_guest_tools = UNSET_VALUE
|
10
15
|
@customizations = []
|
11
16
|
@destroy_unused_network_interfaces = UNSET_VALUE
|
12
17
|
@network_adapters = {}
|
@@ -21,8 +26,8 @@ module VagrantPlugins
|
|
21
26
|
@customizations << [event, command]
|
22
27
|
end
|
23
28
|
|
24
|
-
def network_adapter(slot, type,
|
25
|
-
@network_adapters[slot] = [type,
|
29
|
+
def network_adapter(slot, type, **opts)
|
30
|
+
@network_adapters[slot] = [type, opts]
|
26
31
|
end
|
27
32
|
|
28
33
|
# @param size [Integer, String] the memory size in MB
|
@@ -35,6 +40,10 @@ module VagrantPlugins
|
|
35
40
|
end
|
36
41
|
|
37
42
|
def finalize!
|
43
|
+
if @check_guest_tools == UNSET_VALUE
|
44
|
+
@check_guest_tools = true
|
45
|
+
end
|
46
|
+
|
38
47
|
if @destroy_unused_network_interfaces == UNSET_VALUE
|
39
48
|
@destroy_unused_network_interfaces = true
|
40
49
|
end
|
@@ -0,0 +1,281 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
|
3
|
+
require 'vagrant/util/busy'
|
4
|
+
require 'vagrant/util/network_ip'
|
5
|
+
require 'vagrant/util/platform'
|
6
|
+
require 'vagrant/util/retryable'
|
7
|
+
require 'vagrant/util/subprocess'
|
8
|
+
|
9
|
+
module VagrantPlugins
|
10
|
+
module Parallels
|
11
|
+
module Driver
|
12
|
+
# Base class for all Parallels drivers.
|
13
|
+
#
|
14
|
+
# This class provides useful tools for things such as executing
|
15
|
+
# PrlCtl and handling SIGINTs and so on.
|
16
|
+
class Base
|
17
|
+
# Include this so we can use `Subprocess` more easily.
|
18
|
+
include Vagrant::Util::Retryable
|
19
|
+
include Vagrant::Util::NetworkIP
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
@logger = Log4r::Logger.new("vagrant::provider::parallels::base")
|
23
|
+
|
24
|
+
# This flag is used to keep track of interrupted state (SIGINT)
|
25
|
+
@interrupted = false
|
26
|
+
|
27
|
+
# Set the list of required CLI utils
|
28
|
+
@cli_paths = {
|
29
|
+
:prlctl => "prlctl",
|
30
|
+
:prlsrvctl => "prlsrvctl",
|
31
|
+
:prl_disk_tool => "prl_disk_tool",
|
32
|
+
:ifconfig => "ifconfig"
|
33
|
+
}
|
34
|
+
|
35
|
+
@cli_paths.each do |name, path|
|
36
|
+
@logger.info("CLI utility '#{name}' path: #{path}")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Clears the shared folders that have been set on the virtual machine.
|
41
|
+
def clear_shared_folders
|
42
|
+
end
|
43
|
+
|
44
|
+
# Creates a host only network with the given options.
|
45
|
+
#
|
46
|
+
# @param [Hash] options Options to create the host only network.
|
47
|
+
# @return [Hash] The details of the host only network, including
|
48
|
+
# keys `:name`, `:bound_to`, `:ip`, `:netmask` and `:dhcp`
|
49
|
+
def create_host_only_network(options)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Deletes the virtual machine references by this driver.
|
53
|
+
def delete
|
54
|
+
end
|
55
|
+
|
56
|
+
# Deletes all disabled network adapters from the VM configuration
|
57
|
+
def delete_disabled_adapters
|
58
|
+
end
|
59
|
+
|
60
|
+
# Deletes any host only networks that aren't being used for anything.
|
61
|
+
def delete_unused_host_only_networks
|
62
|
+
end
|
63
|
+
|
64
|
+
# Enables network adapters on the VM.
|
65
|
+
#
|
66
|
+
# The format of each adapter specification should be like so:
|
67
|
+
#
|
68
|
+
# {
|
69
|
+
# :type => :hostonly,
|
70
|
+
# :hostonly => "vagrant-vnet0",
|
71
|
+
# :bound_to => "vnic2",
|
72
|
+
# :nic_type => "virtio"
|
73
|
+
# }
|
74
|
+
#
|
75
|
+
# This must support setting up both host only and bridged networks.
|
76
|
+
#
|
77
|
+
# @param [Array<Hash>] adapters Array of adapters to enable.
|
78
|
+
def enable_adapters(adapters)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Execute a raw command straight through to 'prlctl' utility
|
82
|
+
#
|
83
|
+
# Accepts a :prlsrvctl as a first element of command if the command
|
84
|
+
# should be executed through to 'prlsrvctl' utility
|
85
|
+
#
|
86
|
+
# Accepts a :retryable => true option if the command should be retried
|
87
|
+
# upon failure.
|
88
|
+
#
|
89
|
+
# Raises a prlctl error if it fails.
|
90
|
+
#
|
91
|
+
# @param [Array] command Command to execute.
|
92
|
+
def execute_command(command)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Exports the virtual machine to the given path.
|
96
|
+
#
|
97
|
+
# @param [String] path Path to the OVF file.
|
98
|
+
# @yield [progress] Yields the block with the progress of the export.
|
99
|
+
def export(path)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Halts the virtual machine (pulls the plug).
|
103
|
+
def halt
|
104
|
+
end
|
105
|
+
|
106
|
+
# Imports the VM by cloning from registered template.
|
107
|
+
#
|
108
|
+
# @param [String] template_uuid Registered template UUID.
|
109
|
+
# @return [String] UUID of the imported VM.
|
110
|
+
def import(template_uuid)
|
111
|
+
end
|
112
|
+
|
113
|
+
# Parses given block (JSON string) to object
|
114
|
+
def json(default=nil)
|
115
|
+
data = yield
|
116
|
+
JSON.parse(data) rescue default
|
117
|
+
end
|
118
|
+
|
119
|
+
# Returns the maximum number of network adapters.
|
120
|
+
def max_network_adapters
|
121
|
+
16
|
122
|
+
end
|
123
|
+
|
124
|
+
# Returns a list of bridged interfaces.
|
125
|
+
#
|
126
|
+
# @return [Hash]
|
127
|
+
def read_bridged_interfaces
|
128
|
+
end
|
129
|
+
|
130
|
+
# Returns the guest tools version that is installed on this VM.
|
131
|
+
#
|
132
|
+
# @return [String]
|
133
|
+
def read_guest_tools_version
|
134
|
+
end
|
135
|
+
|
136
|
+
# Returns a list of available host only interfaces.
|
137
|
+
#
|
138
|
+
# @return [Hash]
|
139
|
+
def read_host_only_interfaces
|
140
|
+
end
|
141
|
+
|
142
|
+
# Returns the MAC address of the first network interface.
|
143
|
+
#
|
144
|
+
# @return [String]
|
145
|
+
def read_mac_address
|
146
|
+
end
|
147
|
+
|
148
|
+
# Returns a list of network interfaces of the VM.
|
149
|
+
#
|
150
|
+
# @return [Hash]
|
151
|
+
def read_network_interfaces
|
152
|
+
end
|
153
|
+
|
154
|
+
# Returns the current state of this VM.
|
155
|
+
#
|
156
|
+
# @return [Symbol]
|
157
|
+
def read_state
|
158
|
+
end
|
159
|
+
|
160
|
+
# Returns a list of all registered
|
161
|
+
# virtual machines and templates.
|
162
|
+
#
|
163
|
+
# @return [Hash]
|
164
|
+
def read_vms
|
165
|
+
end
|
166
|
+
|
167
|
+
# Resumes the virtual machine.
|
168
|
+
#
|
169
|
+
def resume(mac)
|
170
|
+
end
|
171
|
+
|
172
|
+
# Sets the MAC address of the first network adapter.
|
173
|
+
#
|
174
|
+
# @param [String] mac MAC address without any spaces/hyphens.
|
175
|
+
def set_mac_address(mac)
|
176
|
+
end
|
177
|
+
|
178
|
+
# Sets the VM name.
|
179
|
+
#
|
180
|
+
# @param [String] name New VM name.
|
181
|
+
def set_name(name)
|
182
|
+
end
|
183
|
+
|
184
|
+
# Share a set of folders on this VM.
|
185
|
+
#
|
186
|
+
# @param [Array<Hash>] folders
|
187
|
+
def share_folders(folders)
|
188
|
+
end
|
189
|
+
|
190
|
+
# Reads the SSH port of this VM.
|
191
|
+
#
|
192
|
+
# @param [Integer] expected Expected guest port of SSH.
|
193
|
+
def ssh_port(expected)
|
194
|
+
end
|
195
|
+
|
196
|
+
# Starts the virtual machine.
|
197
|
+
#
|
198
|
+
def start
|
199
|
+
end
|
200
|
+
|
201
|
+
# Suspend the virtual machine.
|
202
|
+
def suspend
|
203
|
+
end
|
204
|
+
|
205
|
+
# Verifies that the driver is ready to accept work.
|
206
|
+
#
|
207
|
+
# This should raise a VagrantError if things are not ready.
|
208
|
+
def verify!
|
209
|
+
end
|
210
|
+
|
211
|
+
# Checks if a VM with the given UUID exists.
|
212
|
+
#
|
213
|
+
# @return [Boolean]
|
214
|
+
def vm_exists?(uuid)
|
215
|
+
end
|
216
|
+
|
217
|
+
# Execute the given subcommand for PrlCtl and return the output.
|
218
|
+
def execute(*command, &block)
|
219
|
+
# Get the options hash if it exists
|
220
|
+
opts = {}
|
221
|
+
opts = command.pop if command.last.is_a?(Hash)
|
222
|
+
|
223
|
+
tries = opts[:retryable] ? 3 : 0
|
224
|
+
|
225
|
+
# Variable to store our execution result
|
226
|
+
r = nil
|
227
|
+
|
228
|
+
retryable(:on => VagrantPlugins::Parallels::Errors::PrlCtlError, :tries => tries, :sleep => 1) do
|
229
|
+
# If there is an error with PrlCtl, this gets set to true
|
230
|
+
errored = false
|
231
|
+
|
232
|
+
# Execute the command
|
233
|
+
r = raw(*command, &block)
|
234
|
+
|
235
|
+
# If the command was a failure, then raise an exception that is
|
236
|
+
# nicely handled by Vagrant.
|
237
|
+
if r.exit_code != 0
|
238
|
+
if @interrupted
|
239
|
+
@logger.info("Exit code != 0, but interrupted. Ignoring.")
|
240
|
+
else
|
241
|
+
errored = true
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
# If there was an error running prlctl, show the error and the
|
246
|
+
# output.
|
247
|
+
if errored
|
248
|
+
raise VagrantPlugins::Parallels::Errors::PrlCtlError,
|
249
|
+
:command => command.inspect,
|
250
|
+
:stderr => r.stderr
|
251
|
+
end
|
252
|
+
end
|
253
|
+
r.stdout
|
254
|
+
end
|
255
|
+
|
256
|
+
# Executes a command and returns the raw result object.
|
257
|
+
def raw(*command, &block)
|
258
|
+
int_callback = lambda do
|
259
|
+
@interrupted = true
|
260
|
+
|
261
|
+
# We have to execute this in a thread due to trap contexts
|
262
|
+
# and locks.
|
263
|
+
Thread.new { @logger.info("Interrupted.") }
|
264
|
+
end
|
265
|
+
|
266
|
+
# Append in the options for subprocess
|
267
|
+
command << { :notify => [:stdout, :stderr] }
|
268
|
+
|
269
|
+
# Get the utility from the first argument:
|
270
|
+
# 'prlctl' by default
|
271
|
+
util = @cli_paths.has_key?(command.first) ? command.delete_at(0) : :prlctl
|
272
|
+
cli = @cli_paths[util]
|
273
|
+
|
274
|
+
Vagrant::Util::Busy.busy(int_callback) do
|
275
|
+
Vagrant::Util::Subprocess.execute(cli, *command, &block)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
3
|
+
require "log4r"
|
4
|
+
|
5
|
+
require File.expand_path("../base", __FILE__)
|
6
|
+
|
7
|
+
module VagrantPlugins
|
8
|
+
module Parallels
|
9
|
+
module Driver
|
10
|
+
class Meta < Base
|
11
|
+
# This is raised if the VM is not found when initializing a driver
|
12
|
+
# with a UUID.
|
13
|
+
class VMNotFound < StandardError; end
|
14
|
+
|
15
|
+
# We use forwardable to do all our driver forwarding
|
16
|
+
extend Forwardable
|
17
|
+
|
18
|
+
# The UUID of the virtual machine we represent
|
19
|
+
attr_reader :uuid
|
20
|
+
|
21
|
+
# The version of Parallels Desktop that is running.
|
22
|
+
attr_reader :version
|
23
|
+
|
24
|
+
def initialize(uuid=nil)
|
25
|
+
# Setup the base
|
26
|
+
super()
|
27
|
+
|
28
|
+
@logger = Log4r::Logger.new("vagrant::provider::parallels::meta")
|
29
|
+
@uuid = uuid
|
30
|
+
|
31
|
+
# Read and assign the version of Parallels Desktop we know which
|
32
|
+
# specific driver to instantiate.
|
33
|
+
begin
|
34
|
+
@version = read_version || ""
|
35
|
+
rescue Vagrant::Errors::CommandUnavailable,
|
36
|
+
Vagrant::Errors::CommandUnavailableWindows
|
37
|
+
# This means that Parallels Desktop was not found, so we raise this
|
38
|
+
# error here.
|
39
|
+
raise VagrantPlugins::Parallels::Errors::ParallelsNotDetected
|
40
|
+
end
|
41
|
+
|
42
|
+
# Instantiate the proper version driver for VirtualBox
|
43
|
+
@logger.debug("Finding driver for Parallels Desktop version: #{@version}")
|
44
|
+
driver_map = {
|
45
|
+
#TODO: Use customized class for each version
|
46
|
+
"8" => PD_8,
|
47
|
+
"9" => PD_9,
|
48
|
+
"10" => PD_9
|
49
|
+
}
|
50
|
+
|
51
|
+
driver_klass = nil
|
52
|
+
driver_map.each do |key, klass|
|
53
|
+
if @version.start_with?(key)
|
54
|
+
driver_klass = klass
|
55
|
+
break
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
if !driver_klass
|
60
|
+
supported_versions = driver_map.keys.sort.join(", ")
|
61
|
+
raise VagrantPlugins::Parallels::Errors::ParallelsInvalidVersion,
|
62
|
+
supported_versions: supported_versions
|
63
|
+
end
|
64
|
+
|
65
|
+
@logger.info("Using Parallels driver: #{driver_klass}")
|
66
|
+
@driver = driver_klass.new(@uuid)
|
67
|
+
|
68
|
+
if @uuid
|
69
|
+
# Verify the VM exists, and if it doesn't, then don't worry
|
70
|
+
# about it (mark the UUID as nil)
|
71
|
+
raise VMNotFound if !@driver.vm_exists?(@uuid)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def_delegators :@driver,
|
76
|
+
#:clear_forwarded_ports,
|
77
|
+
:clear_shared_folders,
|
78
|
+
:compact,
|
79
|
+
:create_host_only_network,
|
80
|
+
:delete,
|
81
|
+
:delete_disabled_adapters,
|
82
|
+
:delete_unused_host_only_networks,
|
83
|
+
:enable_adapters,
|
84
|
+
:execute_command,
|
85
|
+
:export,
|
86
|
+
#:forward_ports,
|
87
|
+
:halt,
|
88
|
+
:import,
|
89
|
+
:read_ip_dhcp,
|
90
|
+
#:read_forwarded_ports,
|
91
|
+
:read_bridged_interfaces,
|
92
|
+
:read_guest_tools_version,
|
93
|
+
:read_guest_ip,
|
94
|
+
:read_guest_property,
|
95
|
+
:read_host_only_interfaces,
|
96
|
+
:read_mac_address,
|
97
|
+
:read_network_interfaces,
|
98
|
+
:read_settings,
|
99
|
+
:read_state,
|
100
|
+
:read_used_ports,
|
101
|
+
:read_virtual_networks,
|
102
|
+
:read_vms,
|
103
|
+
:read_vms_info,
|
104
|
+
:read_vms_paths,
|
105
|
+
:register,
|
106
|
+
:registered?,
|
107
|
+
:resume,
|
108
|
+
:set_mac_address,
|
109
|
+
:set_name,
|
110
|
+
:share_folders,
|
111
|
+
:ssh_port,
|
112
|
+
:start,
|
113
|
+
:suspend,
|
114
|
+
:unregister,
|
115
|
+
:verify!,
|
116
|
+
:vm_exists?
|
117
|
+
|
118
|
+
protected
|
119
|
+
|
120
|
+
# This returns the version of Parallels Desktop that is running.
|
121
|
+
#
|
122
|
+
# @return [String]
|
123
|
+
def read_version
|
124
|
+
# The version string is usually in one of the following formats:
|
125
|
+
#
|
126
|
+
# * 8.0.12345.123456
|
127
|
+
# * 9.0.12345.123456
|
128
|
+
|
129
|
+
if execute('--version', retryable: true) =~ /prlctl version ([\d\.]+)/
|
130
|
+
return $1.downcase
|
131
|
+
else
|
132
|
+
return nil
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|