vagrant-parallels 0.0.4 → 0.0.5

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.
data/.gitignore CHANGED
@@ -21,3 +21,4 @@ Vagrantfile
21
21
  .vagrant
22
22
  *.box
23
23
  *.pyc
24
+ sandi_meter
data/README.md CHANGED
@@ -1,14 +1,14 @@
1
1
  # Vagrant Parallels Provider
2
2
 
3
- This is a [Vagrant](http://www.vagrantup.com) 1.3+ plugin that adds an [Parallels Desktop](http://www.parallels.com/products/desktop/)
4
- provider to Vagrant, allowing Vagrant to control and provision machines using Parallels Desktop insead of the default Virtualbox.
3
+ This is a [Vagrant](http://www.vagrantup.com) 1.3+ plugin that adds a [Parallels Desktop](http://www.parallels.com/products/desktop/)
4
+ provider to Vagrant, allowing Vagrant to control and provision machines using Parallels Desktop instead of the default Virtualbox.
5
5
 
6
6
  ## Note
7
7
 
8
- This project is still in active development and not all vagrant features have been developed, please report any issues you might find.
9
- Almost all features are available except for exporting/packaging VM's this will be available soon.
8
+ This project is still in active development and not all vagrant features have been developed, so please report any issues you might find.
9
+ Almost all features are available except for exporting/packaging VM's. This will be available soon.
10
10
 
11
- We look forward to hearing from you with any issues or features, Thank you
11
+ We look forward to hearing from you with any issues or features. Thank you!
12
12
 
13
13
  ## Usage
14
14
  Install using standard Vagrant 1.1+ plugin installation methods. After installing, then do a `vagrant up` and specify the `parallels` provider. An example is shown below.
@@ -21,7 +21,27 @@ $ vagrant up --provider=parallels
21
21
  ...
22
22
  ```
23
23
 
24
- You need to have a paralles compatible box file installed before doing a `vagrnat up`, please refer to the coming section for instaructions.
24
+ You need to have a parallels compatible box file installed before doing a `vagrant up`, please refer to the coming section for instructions.
25
+
26
+ ### Default Provider
27
+
28
+ When using parallels as your vagrant provider after almost every command you will need to append `--provider=parallels`. To simplify this you can set your default vagrant provider as **parallels**
29
+
30
+ If you're using BASH
31
+
32
+ ```
33
+ # Append to bash
34
+ echo "export VAGRANT_DEFAULT_PROVIDER=parallels" | tee -a ~/.bashrc
35
+ source ~/.bashrc
36
+ ```
37
+
38
+ If you're using ZSH
39
+
40
+ ```
41
+ # Append to zsh
42
+ echo "export VAGRANT_DEFAULT_PROVIDER=parallels" | tee -a ~/.zshrc
43
+ source ~/.zshrc
44
+ ```
25
45
 
26
46
  ## Box Format
27
47
 
@@ -40,6 +60,29 @@ The box format is basically just the required `metadata.json` file
40
60
  along with a `Vagrantfile` that does default settings for the
41
61
  provider-specific configuration for this provider.
42
62
 
63
+ ## Networking
64
+ By default 'vagrant-parallels' uses the basic Vagrant networking approach. By default VM has one adapter assigned to the 'Shared' network in Parallels Desktop.
65
+ But you can also add one ore more `:private_network` adapters, as described below:
66
+
67
+ ### Private Network
68
+ It is fully compatible with basic Vagrant [Private Networking](http://docs.vagrantup.com/v2/networking/private_network.html).
69
+ #### Available arguments:
70
+ - `type` - IP configuration way: `:static` or `:dhcp`. Default is `:static`. If `:dchp` is set, such interface will get an IP dynamically from default subnet "10.37.129.1/255.255.255.0".
71
+ - `ip` - IP address which will be assigned to this network adapter. It is required only if type is `:static`.
72
+ - `netmask` - network mask. Default is `"255.255.255.0"`. It is required only if type is `:static`.
73
+ - `nic_type` - Unnecessary argument, means the type of network adapter. Can be any of `"virtio"`, `"e1000"` or `"rtl"`. Default is `"e1000"`.
74
+
75
+ #### Example:
76
+ ```ruby
77
+ Vagrant.configure("2") do |config|
78
+ config.vm.network :private_network, ip: "33.33.33.50", netmask: "255.255.0.0"
79
+ config.vm.network :private_network, type: :dhcp, nic_type: "rtl"
80
+ end
81
+ ```
82
+ It means that two private network adapters will be configured:
83
+ 1) The first will have static ip '33.33.33.50' and mask '255.255.0.0'. It will be represented as device `"e1000"` by default (e.g. 'Intel(R) PRO/1000 MT').
84
+ 2) The second adapter will be configured as `"rtl"` ('Realtek RTL8029AS') and get an IP from internal DHCP server, which is working on the default network "10.37.129.1/255.255.255.0".
85
+
43
86
  ## Development
44
87
 
45
88
  To work on the `vagrant-parallels` plugin, clone this repository out
@@ -70,7 +113,7 @@ and add the following line to your `Vagrantfile`
70
113
  Vagrant.require_plugin "vagrant-parallels"
71
114
  ```
72
115
 
73
- You need to have a compatable box file installed, refer to box file section
116
+ You need to have a compatible box file installed, refer to box file section
74
117
 
75
118
  Use bundler to execute Vagrant:
76
119
 
@@ -89,4 +132,16 @@ $ rake build
89
132
  $ vagrant plugin install ./pkg/vagrant-parallels-<version>.gem
90
133
  ...
91
134
  ```
92
- So, now you have your own plugin installed, check it by command `vagrant plugin list`
135
+ So, now that you have your own plugin installed, check it with the command `vagrant plugin list`
136
+
137
+ ## Contributors
138
+
139
+ A great thanks to the people who helping this project stand on its feet, thank you
140
+
141
+ * Kevin Kaland `@wizonesolutions`
142
+ * Mikhail Zholobov `@legal90`
143
+ * Dmytro Vasylenko `@odi-um`
144
+ * Thomas Koschate `@koschate`
145
+
146
+ and to all the people who are using and testing this tool
147
+
@@ -23,12 +23,14 @@ module VagrantPlugins
23
23
  #b.use PrepareNFSSettings
24
24
  b.use ClearSharedFolders
25
25
  b.use ShareFolders
26
+ b.use Network
26
27
  b.use ClearNetworkInterfaces
27
- # b.use Network
28
28
  # b.use ForwardPorts
29
29
  b.use SetHostname
30
30
  # b.use SaneDefaults
31
+ b.use Customize, "pre-boot"
31
32
  b.use Boot
33
+ b.use Customize, "post-boot"
32
34
  b.use WaitForCommunicator
33
35
  b.use CheckGuestTools
34
36
  end
@@ -53,6 +55,7 @@ module VagrantPlugins
53
55
  b3.use action_halt
54
56
  b3.use UnregisterTemplate
55
57
  b3.use Destroy
58
+ b3.use DestroyUnusedNetworkInterfaces
56
59
  else
57
60
  b3.use MessageWillNotDestroy
58
61
  end
@@ -255,6 +258,7 @@ module VagrantPlugins
255
258
  b2.use CheckAccessible
256
259
  b2.use HandleBoxUrl
257
260
  b2.use RegisterTemplate
261
+ b2.use Customize, "pre-import"
258
262
  b2.use Import
259
263
  b2.use UnregisterTemplate
260
264
  b2.use MatchMACAddress
@@ -274,7 +278,9 @@ module VagrantPlugins
274
278
  autoload :ClearNetworkInterfaces, File.expand_path("../action/clear_network_interfaces", __FILE__)
275
279
  autoload :ClearSharedFolders, File.expand_path("../action/clear_shared_folders", __FILE__)
276
280
  autoload :Created, File.expand_path("../action/created", __FILE__)
281
+ autoload :Customize, File.expand_path("../action/customize", __FILE__)
277
282
  autoload :Destroy, File.expand_path("../action/destroy", __FILE__)
283
+ autoload :DestroyUnusedNetworkInterfaces, File.expand_path("../action/destroy_unused_network_interfaces", __FILE__)
278
284
  autoload :Export, File.expand_path("../action/export", __FILE__)
279
285
  autoload :ForcedHalt, File.expand_path("../action/forced_halt", __FILE__)
280
286
  autoload :Import, File.expand_path("../action/import", __FILE__)
@@ -286,6 +292,7 @@ module VagrantPlugins
286
292
  autoload :MessageNotCreated, File.expand_path("../action/message_not_created", __FILE__)
287
293
  autoload :MessageNotRunning, File.expand_path("../action/message_not_running", __FILE__)
288
294
  autoload :MessageWillNotDestroy, File.expand_path("../action/message_will_not_destroy", __FILE__)
295
+ autoload :Network, File.expand_path("../action/network", __FILE__)
289
296
  autoload :Package, File.expand_path("../action/package", __FILE__)
290
297
  autoload :PackageConfigFiles, File.expand_path("../action/package_config_files", __FILE__)
291
298
  autoload :PruneNFSExports, File.expand_path("../action/prune_nfs_exports", __FILE__)
@@ -7,8 +7,6 @@ module VagrantPlugins
7
7
  end
8
8
 
9
9
  def call(env)
10
- # Use the raw interface for now, while the virtualbox gem
11
- # doesn't support guest properties (due to cross platform issues)
12
10
  tools_version = env[:machine].provider.driver.read_guest_tools_version
13
11
  if !tools_version
14
12
  env[:ui].warn I18n.t("vagrant.actions.vm.check_guest_tools.not_detected")
@@ -16,7 +14,7 @@ module VagrantPlugins
16
14
  env[:machine].provider.driver.verify! =~ /^[\w\s]+ ([\d.]+)$/
17
15
  os_version = $1
18
16
  unless os_version.start_with? tools_version
19
- env[:ui].warn(I18n.t("vagrant.actions.vm.check_guest_tools.version_mismatch",
17
+ env[:ui].warn(I18n.t("vagrant_parallels.actions.vm.check_guest_tools.version_mismatch",
20
18
  tools_version: tools_version,
21
19
  parallels_version: os_version))
22
20
  end
@@ -7,7 +7,7 @@ module VagrantPlugins
7
7
  end
8
8
 
9
9
  def call(env)
10
- # "Enable" all the adapters we setup.
10
+ # Delete all disabled network adapters
11
11
  env[:ui].info I18n.t("vagrant.actions.vm.clear_network_interfaces.deleting")
12
12
  env[:machine].provider.driver.delete_adapters
13
13
 
@@ -0,0 +1,43 @@
1
+ module VagrantPlugins
2
+ module Parallels
3
+ module Action
4
+ class Customize
5
+ def initialize(app, env, event)
6
+ @app = app
7
+ @event = event
8
+ end
9
+
10
+ def call(env)
11
+ customizations = []
12
+ env[:machine].provider_config.customizations.each do |event, command|
13
+ if event == @event
14
+ customizations << command
15
+ end
16
+ end
17
+
18
+ if !customizations.empty?
19
+ env[:ui].info I18n.t("vagrant.actions.vm.customize.running", event: @event)
20
+
21
+ # Execute each customization command.
22
+ customizations.each do |command|
23
+ processed_command = command.collect do |arg|
24
+ arg = env[:machine].id if arg == :id
25
+ arg.to_s
26
+ end
27
+
28
+ result = env[:machine].provider.driver.set_vm_settings(processed_command)
29
+ if result.exit_code != 0
30
+ raise Vagrant::Errors::VMCustomizationFailed, {
31
+ :command => processed_command.inspect,
32
+ :error => result.stderr
33
+ }
34
+ end
35
+ end
36
+ end
37
+
38
+ @app.call(env)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,22 @@
1
+ require "log4r"
2
+
3
+ module VagrantPlugins
4
+ module Parallels
5
+ module Action
6
+ class DestroyUnusedNetworkInterfaces
7
+ def initialize(app, env)
8
+ @app = app
9
+ end
10
+
11
+ def call(env)
12
+ if env[:machine].provider_config.destroy_unused_network_interfaces
13
+ env[:ui].info I18n.t("vagrant.actions.vm.destroy_network.destroying")
14
+ env[:machine].provider.driver.delete_unused_host_only_networks
15
+ end
16
+
17
+ @app.call(env)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,272 @@
1
+ require "set"
2
+
3
+ require "log4r"
4
+
5
+ require "vagrant/util/network_ip"
6
+ require "vagrant/util/scoped_hash_override"
7
+
8
+ module VagrantPlugins
9
+ module Parallels
10
+ module Action
11
+ # This middleware class sets up all networking for the Parallels Desktop
12
+ # instance. This includes host only networks, bridged networking,
13
+ # forwarded ports, etc.
14
+ #
15
+ # This handles all the `config.vm.network` configurations.
16
+ class Network
17
+ include Vagrant::Util::NetworkIP
18
+ include Vagrant::Util::ScopedHashOverride
19
+
20
+ def initialize(app, env)
21
+ @app = app
22
+ @logger = Log4r::Logger.new("vagrant::plugins::parallels::network")
23
+ end
24
+
25
+ def call(env)
26
+ @env = env
27
+ # Get the list of network adapters from the configuration
28
+ network_adapters_config = env[:machine].provider_config.network_adapters.dup
29
+
30
+ # Assign the adapter slot for each high-level network
31
+ available_slots = Set.new(0..7)
32
+ network_adapters_config.each do |slot, _data|
33
+ available_slots.delete(slot)
34
+ end
35
+
36
+ @logger.debug("Available slots for high-level adapters: #{available_slots.inspect}")
37
+ @logger.info("Determining network adapters required for high-level configuration...")
38
+ available_slots = available_slots.to_a.sort
39
+ env[:machine].config.vm.networks.each do |type, options|
40
+ # We only handle private and public networks
41
+ next if type != :private_network && type != :public_network
42
+
43
+ options = scoped_hash_override(options, :parallels)
44
+
45
+ # Figure out the slot that this adapter will go into
46
+ slot = options[:adapter]
47
+ if !slot
48
+ if available_slots.empty?
49
+ raise VagrantPlugins::Parallels::Errors::ParallelsNoRoomForHighLevelNetwork
50
+ end
51
+
52
+ slot = available_slots.shift
53
+ end
54
+
55
+ # Configure it
56
+ data = nil
57
+ if type == :private_network
58
+ # private_network = hostonly
59
+ data = [:hostonly, options]
60
+ elsif type == :public_network
61
+ # public_network = bridged
62
+ data = [:bridged, options]
63
+ end
64
+
65
+ # Store it!
66
+ @logger.info(" -- Slot #{slot}: #{data[0]}")
67
+ network_adapters_config[slot] = data
68
+ end
69
+
70
+ @logger.info("Determining adapters and compiling network configuration...")
71
+ adapters = []
72
+ network_adapters_config.each do |slot, data|
73
+ type = data[0]
74
+ options = data[1]
75
+
76
+ @logger.info("Network slot #{slot}. Type: #{type}.")
77
+
78
+ # Get the normalized configuration for this type
79
+ config = send("#{type}_config", options)
80
+ config[:adapter] = slot
81
+ @logger.debug("Normalized configuration: #{config.inspect}")
82
+
83
+ # Get the virtual network adapter configuration
84
+ adapter = send("#{type}_adapter", config)
85
+ adapters << adapter
86
+ @logger.debug("Adapter configuration: #{adapter.inspect}")
87
+ end
88
+
89
+ if !adapters.empty?
90
+ # Enable the adapters
91
+ @logger.info("Enabling adapters...")
92
+ env[:ui].info I18n.t("vagrant.actions.vm.network.preparing")
93
+ env[:machine].provider.driver.enable_adapters(adapters)
94
+ end
95
+
96
+ # Continue the middleware chain.
97
+ @app.call(env)
98
+
99
+ end
100
+
101
+ def hostonly_config(options)
102
+ options = {
103
+ :mac => nil,
104
+ :nic_type => "e1000",
105
+ :netmask => "255.255.255.0",
106
+ :type => :static
107
+ }.merge(options)
108
+
109
+ # Make sure the type is a symbol
110
+ options[:type] = options[:type].to_sym
111
+
112
+ # Default IP is in the 20-bit private network block for DHCP based networks
113
+ options[:ip] = "10.37.129.1" if options[:type] == :dhcp && !options[:ip]
114
+
115
+ # Calculate our network address for the given IP/netmask
116
+ netaddr = network_address(options[:ip], options[:netmask])
117
+
118
+ # Verify that a host-only network subnet would not collide
119
+ # with a bridged networking interface.
120
+ #
121
+ # If the subnets overlap in any way then the host only network
122
+ # will not work because the routing tables will force the
123
+ # traffic onto the real interface rather than the virtual
124
+ # network interface.
125
+ @env[:machine].provider.driver.read_bridged_interfaces.each do |interface|
126
+ that_netaddr = network_address(interface[:ip], interface[:netmask])
127
+ raise Vagrant::Errors::NetworkCollision if \
128
+ netaddr == that_netaddr && interface[:status] != "Down"
129
+ end
130
+
131
+ # Split the IP address into its components
132
+ ip_parts = netaddr.split(".").map { |i| i.to_i }
133
+
134
+ # Calculate the adapter IP, which we assume is the IP ".1" at
135
+ # the end usually.
136
+ adapter_ip = ip_parts.dup
137
+ adapter_ip[3] += 1
138
+ options[:adapter_ip] ||= adapter_ip.join(".")
139
+
140
+ dhcp_options = {}
141
+ if options[:type] == :dhcp
142
+ # Calculate the DHCP server IP, which is the network address
143
+ # with the final octet + 2. So "172.28.0.0" turns into "172.28.0.2"
144
+ dhcp_ip = ip_parts.dup
145
+ dhcp_ip[3] += 2
146
+ dhcp_options[:dhcp_ip] ||= dhcp_ip.join(".")
147
+
148
+ # Calculate the lower and upper bound for the DHCP server
149
+ dhcp_lower = ip_parts.dup
150
+ dhcp_lower[3] += 3
151
+ dhcp_options[:dhcp_lower] ||= dhcp_lower.join(".")
152
+
153
+ dhcp_upper = ip_parts.dup
154
+ dhcp_upper[3] = 254
155
+ dhcp_options[:dhcp_upper] ||= dhcp_upper.join(".")
156
+ end
157
+
158
+ return {
159
+ :adapter_ip => options[:adapter_ip],
160
+ :ip => options[:ip],
161
+ :mac => options[:mac],
162
+ :netmask => options[:netmask],
163
+ :nic_type => options[:nic_type],
164
+ :type => options[:type],
165
+ }.merge(dhcp_options)
166
+ end
167
+
168
+ def hostonly_adapter(config)
169
+ @logger.info("Searching for matching hostonly network: #{config[:ip]}")
170
+ interface = hostonly_find_matching_network(config)
171
+
172
+ if !interface
173
+ @logger.info("Network not found. Creating if we can.")
174
+
175
+ # It is an error if a specific host only network name was specified
176
+ # but the network wasn't found.
177
+ if config[:name]
178
+ raise Vagrant::Errors::NetworkNotFound, :name => config[:name]
179
+ end
180
+
181
+ # Create a new network
182
+ interface = hostonly_create_network(config)
183
+ @logger.info("Created network: #{interface[:name]}")
184
+ end
185
+
186
+ return {
187
+ :adapter => config[:adapter],
188
+ :hostonly => interface[:name],
189
+ :bound_to => interface[:bound_to],
190
+ :mac => config[:mac],
191
+ :nic_type => config[:nic_type],
192
+ :type => :hostonly,
193
+ :dhcp => interface[:dhcp],
194
+ :ip => config[:ip],
195
+ :netmask => config[:netmask],
196
+ }
197
+ end
198
+
199
+ def shared_config(options)
200
+ return {}
201
+ end
202
+
203
+ def shared_adapter(config)
204
+ return {
205
+ :adapter => config[:adapter],
206
+ :shared => "Shared",
207
+ :type => :shared,
208
+ :dhcp => true,
209
+ :nic_type => "e1000"
210
+ }
211
+ end
212
+
213
+ #-----------------------------------------------------------------
214
+ # Misc. helpers
215
+ #-----------------------------------------------------------------
216
+ # This determines the next free network name
217
+ def next_network_name
218
+ # Get the list of numbers
219
+ net_nums = []
220
+ @env[:machine].provider.driver.read_virtual_networks.each do |net|
221
+ if net['Network ID'] =~ /^vagrant-vnet(\d+)$/
222
+ net_nums << $1.to_i
223
+ end
224
+ end
225
+
226
+ if net_nums.empty?
227
+ "vagrant-vnet0"
228
+ else
229
+ net_nums.sort! if net_nums
230
+ free_names = Array(0..net_nums.last.next) - net_nums
231
+ "vagrant-vnet#{free_names.first}"
232
+ end
233
+ end
234
+
235
+ #-----------------------------------------------------------------
236
+ # Hostonly Helper Functions
237
+ #-----------------------------------------------------------------
238
+ # This creates a host only network for the given configuration.
239
+ def hostonly_create_network(config)
240
+ options = {
241
+ :name => next_network_name,
242
+ :adapter_ip => config[:adapter_ip],
243
+ :netmask => config[:netmask],
244
+ }
245
+
246
+ if config[:type] == :dhcp
247
+ options[:dhcp] = {
248
+ :ip => config[:dhcp_ip],
249
+ :lower => config[:dhcp_lower],
250
+ :upper => config[:dhcp_upper]
251
+ }
252
+ end
253
+
254
+ @env[:machine].provider.driver.create_host_only_network(options)
255
+ end
256
+
257
+ # This finds a matching host only network for the given configuration.
258
+ def hostonly_find_matching_network(config)
259
+ this_netaddr = network_address(config[:ip], config[:netmask])
260
+
261
+ @env[:machine].provider.driver.read_host_only_interfaces.each do |interface|
262
+ return interface if config[:name] && config[:name] == interface[:name]
263
+ return interface if this_netaddr == \
264
+ network_address(interface[:ip], interface[:netmask])
265
+ end
266
+
267
+ nil
268
+ end
269
+ end
270
+ end
271
+ end
272
+ end