vagrant-parallels 0.2.1 → 0.2.2.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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +21 -13
  3. data/.travis.yml +1 -0
  4. data/README.md +43 -54
  5. data/config/i18n-tasks.yml.erb +1 -1
  6. data/debug.log +941 -0
  7. data/lib/vagrant-parallels/action.rb +0 -7
  8. data/lib/vagrant-parallels/action/check_accessible.rb +1 -1
  9. data/lib/vagrant-parallels/action/check_guest_tools.rb +10 -2
  10. data/lib/vagrant-parallels/action/clear_network_interfaces.rb +1 -1
  11. data/lib/vagrant-parallels/action/customize.rb +6 -4
  12. data/lib/vagrant-parallels/action/export.rb +56 -12
  13. data/lib/vagrant-parallels/action/import.rb +49 -30
  14. data/lib/vagrant-parallels/action/network.rb +137 -48
  15. data/lib/vagrant-parallels/action/package_config_files.rb +0 -12
  16. data/lib/vagrant-parallels/action/prepare_nfs_valid_ids.rb +1 -1
  17. data/lib/vagrant-parallels/action/set_name.rb +2 -2
  18. data/lib/vagrant-parallels/config.rb +11 -2
  19. data/lib/vagrant-parallels/driver/base.rb +281 -0
  20. data/lib/vagrant-parallels/driver/meta.rb +138 -0
  21. data/lib/vagrant-parallels/driver/{prl_ctl.rb → pd_8.rb} +116 -256
  22. data/lib/vagrant-parallels/driver/pd_9.rb +417 -0
  23. data/lib/vagrant-parallels/errors.rb +15 -7
  24. data/lib/vagrant-parallels/plugin.rb +7 -7
  25. data/lib/vagrant-parallels/provider.rb +33 -3
  26. data/lib/vagrant-parallels/version.rb +1 -1
  27. data/locales/en.yml +30 -16
  28. data/test/unit/base.rb +1 -5
  29. data/test/unit/config_test.rb +13 -2
  30. data/test/unit/driver/pd_8_test.rb +196 -0
  31. data/test/unit/driver/pd_9_test.rb +196 -0
  32. data/test/unit/locales/locales_test.rb +1 -1
  33. data/test/unit/support/shared/parallels_context.rb +2 -2
  34. data/test/unit/support/shared/pd_driver_examples.rb +243 -0
  35. data/test/unit/synced_folder_test.rb +37 -0
  36. data/vagrant-parallels.gemspec +5 -5
  37. metadata +39 -32
  38. data/lib/vagrant-parallels/action/match_mac_address.rb +0 -28
  39. data/lib/vagrant-parallels/action/register_template.rb +0 -24
  40. data/lib/vagrant-parallels/action/unregister_template.rb +0 -26
  41. data/test/support/isolated_environment.rb +0 -46
  42. data/test/support/tempdir.rb +0 -43
  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)
@@ -8,7 +8,7 @@ module VagrantPlugins
8
8
  end
9
9
 
10
10
  def call(env)
11
- env[:nfs_valid_ids] = env[:machine].provider.driver.read_all_names.values
11
+ env[:nfs_valid_ids] = env[:machine].provider.driver.read_vms.values
12
12
  @app.call(env)
13
13
  end
14
14
  end
@@ -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.read_all_names
32
- raise Vagrant::Errors::VMNameExists, :name => name if \
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, *args)
25
- @network_adapters[slot] = [type, args]
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