Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Add driver for Parallels Desktop 12, drop EOL versions and deprecated options #271

Merged
merged 4 commits into from
Aug 18, 2016
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
driver: Move methods from #pd_10 to #base
  • Loading branch information
legal90 committed Aug 18, 2016
commit bc4cbdd28e4a7c1cf6fb3f12023e73b439b911e0
191 changes: 181 additions & 10 deletions lib/vagrant-parallels/driver/base.rb
Original file line number Diff line number Diff line change
@@ -54,7 +54,14 @@ def initialize(uuid)
# }
#
def clear_forwarded_ports(ports)
raise NotImplementedError
args = []
ports.each do |r|
args.concat(["--nat-#{r[:protocol]}-del", r[:name]])
end

if !args.empty?
execute_prlsrvctl('net', 'set', read_shared_network_id, *args)
end
end

# Clears the shared folders that have been set on the virtual machine.
@@ -187,7 +194,25 @@ def delete_snapshot(uuid, snapshot_id)

# Deletes any host only networks that aren't being used for anything.
def delete_unused_host_only_networks
raise NotImplementedError
networks = read_virtual_networks
# 'Shared'(vnic0) and 'Host-Only'(vnic1) are default in Parallels Desktop
# They should not be deleted anyway.
networks.keep_if do |net|
net['Type'] == 'host-only' && net['Bound To'] &&
net['Bound To'].match(/^(?>vnic|Parallels Host-Only #)(\d+)$/)[1].to_i >= 2
end

read_vms_info.each do |vm|
used_nets = vm.fetch('Hardware', {}).select { |name, _| name.start_with? 'net' }
used_nets.each_value do |net_params|
networks.delete_if { |net| net['Network ID'] == net_params.fetch('iface', nil) }
end
end

networks.each do |net|
# Delete the actual host only network interface.
execute_prlsrvctl('net', 'del', net['Network ID'])
end
end

# Disables requiring password on such operations as creating, adding,
@@ -196,7 +221,10 @@ def delete_unused_host_only_networks
# @param [Array<String>] acts List of actions. Available values:
# ['create-vm', 'add-vm', 'remove-vm', 'clone-vm']
def disable_password_restrictions(acts)
raise NotImplementedError
server_info = json { execute_prlsrvctl('info', '--json') }
server_info.fetch('Require password to',[]).each do |act|
execute_prlsrvctl('set', '--require-pwd', "#{act}:off") if acts.include? act
end
end

# Enables network adapters on the VM.
@@ -215,7 +243,45 @@ def disable_password_restrictions(acts)
# @param [Array<Symbol => Symbol, String>] adapters
# Array of adapters to be enabled.
def enable_adapters(adapters)
raise NotImplementedError
# Get adapters which have already configured for this VM
# Such adapters will be just overridden
existing_adapters = read_settings.fetch('Hardware', {}).keys.select do |name|
name.start_with? 'net'
end

# Disable all previously existing adapters (except shared 'vnet0')
existing_adapters.each do |adapter|
if adapter != 'vnet0'
execute_prlctl('set', @uuid, '--device-set', adapter, '--disable')
end
end

adapters.each do |adapter|
args = []
if existing_adapters.include? "net#{adapter[:adapter]}"
args.concat(['--device-set',"net#{adapter[:adapter]}", '--enable'])
else
args.concat(['--device-add', 'net'])
end

if adapter[:type] == :hostonly
args.concat(['--type', 'host', '--iface', adapter[:hostonly]])
elsif adapter[:type] == :bridged
args.concat(['--type', 'bridged', '--iface', adapter[:bridge]])
elsif adapter[:type] == :shared
args.concat(['--type', 'shared'])
end

if adapter[:mac_address]
args.concat(['--mac', adapter[:mac_address]])
end

if adapter[:nic_type]
args.concat(['--adapter-type', adapter[:nic_type].to_s])
end

execute_prlctl('set', @uuid, *args)
end
end

# Create a set of port forwarding rules for a virtual machine.
@@ -237,7 +303,20 @@ def enable_adapters(adapters)
# @param [Array<Hash>] ports An array of ports to set. See documentation
# for more information on the format.
def forward_ports(ports)
raise NotImplementedError
args = []
ports.each do |options|
protocol = options[:protocol] || 'tcp'
pf_builder = [
options[:name],
options[:hostport],
@uuid,
options[:guestport]
]

args.concat(["--nat-#{protocol}-add", pf_builder.join(',')])
end

execute_prlsrvctl('net', 'set', read_shared_network_id, *args)
end

# Lists all snapshots for the specified VM. Returns an empty hash if
@@ -328,7 +407,13 @@ def read_bridged_interfaces
# Otherwise only rules related to the context VM will be returned.
# @return [Array<Symbol => String>]
def read_forwarded_ports(global=false)
raise NotImplementedError
all_rules = read_shared_interface[:nat]

if global
all_rules
else
all_rules.select { |r| r[:guest].include?(@uuid) }
end
end

# Returns an IP of the virtual machine. It requires that Shared network
@@ -418,7 +503,32 @@ def read_host_info
#
# @return [Array<Symbol => String>]
def read_host_only_interfaces
raise NotImplementedError
net_list = read_virtual_networks
net_list.keep_if { |net| net['Type'] == 'host-only' }

hostonly_ifaces = []
net_list.each do |iface|
net_info = json do
execute_prlsrvctl('net', 'info', iface['Network ID'], '--json')
end

iface = {
name: net_info['Network ID'],
status: 'Down'
}

adapter = net_info['Parallels adapter']
if adapter && net_info['Bound To']
# In PD >= 10.1.2 there are new field names for an IP/Subnet
iface[:ip] = adapter['IP address'] || adapter['IPv4 address']
iface[:netmask] = adapter['Subnet mask'] || adapter['IPv4 subnet mask']
iface[:bound_to] = net_info['Bound To']
iface[:status] = 'Up'
end

hostonly_ifaces << iface
end
hostonly_ifaces
end

# Returns the MAC address of the first Shared network interface.
@@ -448,7 +558,27 @@ def read_mac_addresses
#
# @return [<Integer => Hash>]
def read_network_interfaces
raise NotImplementedError
nics = {}

# Get enabled VM's network interfaces
ifaces = read_settings.fetch('Hardware', {}).keep_if do |dev, params|
dev.start_with?('net') and params.fetch('enabled', true)
end
ifaces.each do |name, params|
adapter = name.match(/^net(\d+)$/)[1].to_i
nics[adapter] ||= {}

if params['type'] == 'shared'
nics[adapter][:type] = :shared
elsif params['type'] == 'host'
nics[adapter][:type] = :hostonly
nics[adapter][:hostonly] = params.fetch('iface','')
elsif params['type'] == 'bridged'
nics[adapter][:type] = :bridged
nics[adapter][:bridge] = params.fetch('iface','')
end
end
nics
end

# Returns virtual machine settings
@@ -472,7 +602,45 @@ def read_shared_network_id
#
# @return [<Symbol => String, Hash>]
def read_shared_interface
raise NotImplementedError
net_info = json do
execute_prlsrvctl('net', 'info', read_shared_network_id, '--json')
end

iface = {
nat: [],
status: 'Down'
}
adapter = net_info['Parallels adapter']

if adapter && net_info['Bound To']
# In PD >= 10.1.2 there are new field names for an IP/Subnet
iface[:ip] = adapter['IP address'] || adapter['IPv4 address']
iface[:netmask] = adapter['Subnet mask'] || adapter['IPv4 subnet mask']
iface[:bound_to] = net_info['Bound To']
iface[:status] = 'Up'
end

if net_info.key?('DHCPv4 server')
iface[:dhcp] = {
ip: net_info['DHCPv4 server']['Server address'],
lower: net_info['DHCPv4 server']['IP scope start address'],
upper: net_info['DHCPv4 server']['IP scope end address']
}
end

net_info['NAT server'].each do |group, rules|
rules.each do |name, params|
iface[:nat] << {
name: name,
protocol: group == 'TCP rules' ? 'tcp' : 'udp',
guest: params['destination IP/VM id'],
hostport: params['source port'],
guestport: params['destination port']
}
end
end

iface
end

# Returns a list of shared folders in format:
@@ -501,6 +669,8 @@ def read_state
#
# @return [Array]
def read_used_ports
# Ignore our own used ports
read_forwarded_ports(true).reject { |r| r[:guest].include?(@uuid) }
end

# Returns the configuration of all virtual networks in Parallels Desktop.
@@ -603,7 +773,8 @@ def set_name(uuid, new_name)
# @param [Boolean] optimized Use "Longer Battery Life"
# instead "Better Performance"
def set_power_consumption_mode(optimized)
raise NotImplementedError
state = optimized ? 'on' : 'off'
execute_prlctl('set', @uuid, '--longer-battery-life', state)
end

# Share a set of folders on this VM.
Loading