Add Parallels virtualisation type
This change adds Parallels support to Ironic ssh driver Change-Id: I5b8ee34f63fd00f9874ce0fe11219224c785c42f Closes-Bug: #1358401
This commit is contained in:
parent
edc9bb038a
commit
75b3568edc
|
@ -23,6 +23,7 @@ For use in dev and test environments.
|
|||
Currently supported environments are:
|
||||
Virtual Box (vbox)
|
||||
Virsh (virsh)
|
||||
Parallels (parallels)
|
||||
"""
|
||||
|
||||
import os
|
||||
|
@ -60,7 +61,7 @@ REQUIRED_PROPERTIES = {
|
|||
"Required."),
|
||||
'ssh_username': _("username to authenticate as. Required."),
|
||||
'ssh_virt_type': _("virtualization software to use; one of vbox, virsh, "
|
||||
"vmware. Required.")
|
||||
"vmware, parallels. Required.")
|
||||
}
|
||||
OTHER_PROPERTIES = {
|
||||
'ssh_key_contents': _("private key(s). One of this, ssh_key_filename, "
|
||||
|
@ -76,6 +77,10 @@ OTHER_PROPERTIES = {
|
|||
COMMON_PROPERTIES = REQUIRED_PROPERTIES.copy()
|
||||
COMMON_PROPERTIES.update(OTHER_PROPERTIES)
|
||||
|
||||
# NOTE(dguerri) Generic boot device map. Virtualisation types that don't define
|
||||
# a more specific one, will use this.
|
||||
# This is left for compatibility with other modules and is still valid for
|
||||
# vbox, virsh and vmware.
|
||||
_BOOT_DEVICES_MAP = {
|
||||
boot_devices.DISK: 'hd',
|
||||
boot_devices.PXE: 'network',
|
||||
|
@ -83,6 +88,21 @@ _BOOT_DEVICES_MAP = {
|
|||
}
|
||||
|
||||
|
||||
def _get_boot_device_map(virt_type):
|
||||
if virt_type in ('vbox', 'virsh', 'vmware'):
|
||||
return _BOOT_DEVICES_MAP
|
||||
elif virt_type == 'parallels':
|
||||
return {
|
||||
boot_devices.DISK: 'hdd0',
|
||||
boot_devices.PXE: 'net0',
|
||||
boot_devices.CDROM: 'cdrom0',
|
||||
}
|
||||
else:
|
||||
raise exception.InvalidParameterValue(_(
|
||||
"SSHPowerDriver '%(virt_type)s' is not a valid virt_type.") %
|
||||
{'virt_type': virt_type})
|
||||
|
||||
|
||||
def _get_command_sets(virt_type):
|
||||
if virt_type == 'vbox':
|
||||
return {
|
||||
|
@ -153,6 +173,24 @@ def _get_command_sets(virt_type):
|
|||
virsh_cmds['base_cmd'] += ' --connect %s' % CONF.ssh.libvirt_uri
|
||||
|
||||
return virsh_cmds
|
||||
elif virt_type == 'parallels':
|
||||
return {
|
||||
'base_cmd': '/usr/bin/prlctl',
|
||||
'start_cmd': 'start {_NodeName_}',
|
||||
'stop_cmd': 'stop {_NodeName_} --kill',
|
||||
'reboot_cmd': 'reset {_NodeName_}',
|
||||
'list_all': "list -a -o name |tail -n +2",
|
||||
'list_running': 'list -o name |tail -n +2',
|
||||
'get_node_macs': ("list -j -i \"{_NodeName_}\" | "
|
||||
"awk -F'\"' '/\"mac\":/ {print $4}' | "
|
||||
"sed 's/\\(..\\)\\(..\\)\\(..\\)\\(..\\)\\(..\\)\\(..\\)/"
|
||||
"\\1:\\2:\\3:\\4:\\5\\6/' | "
|
||||
"tr '[:upper:]' '[:lower:]'"),
|
||||
'set_boot_device': ("{_BaseCmd_} set {_NodeName_} "
|
||||
"--device-bootorder \"{_BootDevice_}\""),
|
||||
'get_boot_device': ("{_BaseCmd_} list -i {_NodeName_} | "
|
||||
"awk '/^Boot order:/ {print $3}'"),
|
||||
}
|
||||
else:
|
||||
raise exception.InvalidParameterValue(_(
|
||||
"SSHPowerDriver '%(virt_type)s' is not a valid virt_type, ") %
|
||||
|
@ -175,12 +213,13 @@ def _get_boot_device(ssh_obj, driver_info):
|
|||
"""
|
||||
cmd_to_exec = driver_info['cmd_set'].get('get_boot_device')
|
||||
if cmd_to_exec:
|
||||
boot_device_map = _get_boot_device_map(driver_info['virt_type'])
|
||||
node_name = _get_hosts_name_for_node(ssh_obj, driver_info)
|
||||
base_cmd = driver_info['cmd_set']['base_cmd']
|
||||
cmd_to_exec = cmd_to_exec.replace('{_NodeName_}', node_name)
|
||||
cmd_to_exec = cmd_to_exec.replace('{_BaseCmd_}', base_cmd)
|
||||
stdout, stderr = _ssh_execute(ssh_obj, cmd_to_exec)
|
||||
return next((dev for dev, hdev in _BOOT_DEVICES_MAP.items()
|
||||
return next((dev for dev, hdev in boot_device_map.items()
|
||||
if hdev == stdout), None)
|
||||
else:
|
||||
raise NotImplementedError()
|
||||
|
@ -596,8 +635,10 @@ class SSHManagement(base.ManagementInterface):
|
|||
"Invalid boot device %s specified.") % device)
|
||||
driver_info['macs'] = driver_utils.get_node_mac_addresses(task)
|
||||
ssh_obj = _get_connection(node)
|
||||
|
||||
boot_device_map = _get_boot_device_map(driver_info['virt_type'])
|
||||
try:
|
||||
_set_boot_device(ssh_obj, driver_info, _BOOT_DEVICES_MAP[device])
|
||||
_set_boot_device(ssh_obj, driver_info, boot_device_map[device])
|
||||
except NotImplementedError:
|
||||
LOG.error(_LE("Failed to set boot device for node %(node)s, "
|
||||
"virt_type %(vtype)s does not support this "
|
||||
|
|
|
@ -181,6 +181,15 @@ class SSHValidateParametersTestCase(base.TestCase):
|
|||
info = ssh._parse_driver_info(node)
|
||||
self.assertEqual(expected_base_cmd, info['cmd_set']['base_cmd'])
|
||||
|
||||
def test__get_boot_device_map_ad_hoc(self):
|
||||
boot_map = ssh._get_boot_device_map('parallels')
|
||||
self.assertEqual('net0', boot_map[boot_devices.PXE])
|
||||
|
||||
def test__get_boot_device_map_exception(self):
|
||||
self.assertRaises(exception.InvalidParameterValue,
|
||||
ssh._get_boot_device_map,
|
||||
'this_doesn_t_exist')
|
||||
|
||||
|
||||
class SSHPrivateMethodsTestCase(base.TestCase):
|
||||
|
||||
|
@ -784,8 +793,25 @@ class SSHDriverTestCase(db_base.DbTestCase):
|
|||
@mock.patch.object(ssh, '_get_connection')
|
||||
@mock.patch.object(ssh, '_get_hosts_name_for_node')
|
||||
@mock.patch.object(ssh, '_ssh_execute')
|
||||
def test_management_interface_set_boot_device_ok(self, mock_exc, mock_h,
|
||||
mock_get_conn):
|
||||
def test_management_interface_set_boot_device_parallels_ok(self, mock_exc,
|
||||
mock_h,
|
||||
mock_get_conn):
|
||||
fake_name = 'fake-name'
|
||||
mock_h.return_value = fake_name
|
||||
mock_get_conn.return_value = self.sshclient
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
task.node['driver_info']['ssh_virt_type'] = 'parallels'
|
||||
self.driver.management.set_boot_device(task, boot_devices.PXE)
|
||||
expected_cmd = ('/usr/bin/prlctl set %s '
|
||||
'--device-bootorder "net0"') % fake_name
|
||||
mock_exc.assert_called_once_with(mock.ANY, expected_cmd)
|
||||
|
||||
@mock.patch.object(ssh, '_get_connection')
|
||||
@mock.patch.object(ssh, '_get_hosts_name_for_node')
|
||||
@mock.patch.object(ssh, '_ssh_execute')
|
||||
def test_management_interface_set_boot_device_virsh_ok(self, mock_exc,
|
||||
mock_h,
|
||||
mock_get_conn):
|
||||
fake_name = 'fake-name'
|
||||
mock_h.return_value = fake_name
|
||||
mock_get_conn.return_value = self.sshclient
|
||||
|
@ -826,8 +852,27 @@ class SSHDriverTestCase(db_base.DbTestCase):
|
|||
@mock.patch.object(ssh, '_get_connection')
|
||||
@mock.patch.object(ssh, '_get_hosts_name_for_node')
|
||||
@mock.patch.object(ssh, '_ssh_execute')
|
||||
def test_management_interface_get_boot_device(self, mock_exc, mock_h,
|
||||
mock_get_conn):
|
||||
def test_management_interface_get_boot_device_parallels(self, mock_exc,
|
||||
mock_h,
|
||||
mock_get_conn):
|
||||
fake_name = 'fake-name'
|
||||
mock_h.return_value = fake_name
|
||||
mock_exc.return_value = ('net0', '')
|
||||
mock_get_conn.return_value = self.sshclient
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
task.node['driver_info']['ssh_virt_type'] = 'parallels'
|
||||
result = self.driver.management.get_boot_device(task)
|
||||
self.assertEqual(boot_devices.PXE, result['boot_device'])
|
||||
expected_cmd = ('/usr/bin/prlctl list -i %s '
|
||||
'| awk \'/^Boot order:/ {print $3}\'') % fake_name
|
||||
mock_exc.assert_called_once_with(mock.ANY, expected_cmd)
|
||||
|
||||
@mock.patch.object(ssh, '_get_connection')
|
||||
@mock.patch.object(ssh, '_get_hosts_name_for_node')
|
||||
@mock.patch.object(ssh, '_ssh_execute')
|
||||
def test_management_interface_get_boot_device_virsh(self, mock_exc,
|
||||
mock_h,
|
||||
mock_get_conn):
|
||||
fake_name = 'fake-name'
|
||||
mock_h.return_value = fake_name
|
||||
mock_exc.return_value = ('network', '')
|
||||
|
|
Loading…
Reference in New Issue