diff options
author | Davide Guerri <davide.guerri@hp.com> | 2014-08-16 02:38:40 +0100 |
---|---|---|
committer | Davide Guerri <davide.guerri@hp.com> | 2014-08-19 16:15:22 +0100 |
commit | 75b3568edce2a48e5112ce4350f989138c376638 (patch) | |
tree | 49616dd35116a9d9ccaf21600e4ab3249e2b90f9 | |
parent | edc9bb038addfc27ffe75ecb81a568c6ebb876c2 (diff) | |
download | ironic-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.py | 47 | ||||
-rw-r--r-- | ironic/tests/drivers/test_ssh.py | 53 |
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', '') |