summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavide Guerri <davide.guerri@hp.com>2014-08-16 02:38:40 +0100
committerDavide Guerri <davide.guerri@hp.com>2014-08-19 16:15:22 +0100
commit75b3568edce2a48e5112ce4350f989138c376638 (patch)
tree49616dd35116a9d9ccaf21600e4ab3249e2b90f9
parentedc9bb038addfc27ffe75ecb81a568c6ebb876c2 (diff)
downloadironic-75b3568edce2a48e5112ce4350f989138c376638.tar.gz
Add Parallels virtualisation type
This change adds Parallels support to Ironic ssh driver Change-Id: I5b8ee34f63fd00f9874ce0fe11219224c785c42f Closes-Bug: #1358401
-rw-r--r--ironic/drivers/modules/ssh.py47
-rw-r--r--ironic/tests/drivers/test_ssh.py53
2 files changed, 93 insertions, 7 deletions
diff --git a/ironic/drivers/modules/ssh.py b/ironic/drivers/modules/ssh.py
index 9795cc439..09b372678 100644
--- a/ironic/drivers/modules/ssh.py
+++ b/ironic/drivers/modules/ssh.py
@@ -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 "
diff --git a/ironic/tests/drivers/test_ssh.py b/ironic/tests/drivers/test_ssh.py
index d018cf7d8..b2be01961 100644
--- a/ironic/tests/drivers/test_ssh.py
+++ b/ironic/tests/drivers/test_ssh.py
@@ -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', '')