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.
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