diff --git a/imagebuild/coreos/oem/cloud-config.yml b/imagebuild/coreos/oem/cloud-config.yml index 01c61f122..b1d303be6 100755 --- a/imagebuild/coreos/oem/cloud-config.yml +++ b/imagebuild/coreos/oem/cloud-config.yml @@ -58,6 +58,8 @@ coreos: --machine=ironic_python_agent \ --bind=/dev:/dev \ --bind=/dev/pts:/dev/pts \ + --bind=/proc:/proc \ + --bind=/sys:/sys \ --bind=/usr/share/oem:/mnt \ --user=root \ --keep-unit \ diff --git a/ironic_python_agent/extensions/standby.py b/ironic_python_agent/extensions/standby.py index 8cb737805..5b9ac4960 100644 --- a/ironic_python_agent/extensions/standby.py +++ b/ironic_python_agent/extensions/standby.py @@ -238,13 +238,21 @@ class StandbyExtension(base.BaseAgentExtension): return 'image ({0}) written to device {1}'.format(image_info['id'], device) - @base.async_command('run_image') - def run_image(self): - script = _path_to_script('shell/reboot.sh') - LOG.info('Rebooting system') - command = ['/bin/bash', script] + def _run_shutdown_script(self, parameter): + script = _path_to_script('shell/shutdown.sh') + command = ['/bin/bash', script, parameter] # this should never return if successful try: stdout, stderr = utils.execute(*command, check_exit_code=[0]) except processutils.ProcessExecutionError as e: raise errors.SystemRebootError(e.exit_code, e.stdout, e.stderr) + + @base.async_command('run_image') + def run_image(self): + LOG.info('Rebooting system') + self._run_shutdown_script('-r') + + @base.async_command('power_off') + def power_off(self): + LOG.info('Powering off system') + self._run_shutdown_script('-h') diff --git a/ironic_python_agent/shell/reboot.sh b/ironic_python_agent/shell/shutdown.sh similarity index 86% rename from ironic_python_agent/shell/reboot.sh rename to ironic_python_agent/shell/shutdown.sh index beb7fce78..3c7738c77 100644 --- a/ironic_python_agent/shell/reboot.sh +++ b/ironic_python_agent/shell/shutdown.sh @@ -22,4 +22,8 @@ set -e echo "1" > /proc/sys/kernel/sysrq echo "s" > /proc/sysrq-trigger -echo "b" > /proc/sysrq-trigger +if [[ $1 = '-h' ]]; then + echo "o" > /proc/sysrq-trigger +elif [[ $1 = '-r' ]]; then + echo "b" > /proc/sysrq-trigger +fi diff --git a/ironic_python_agent/tests/extensions/standby.py b/ironic_python_agent/tests/extensions/standby.py index 73d63aad8..de16f887f 100644 --- a/ironic_python_agent/tests/extensions/standby.py +++ b/ironic_python_agent/tests/extensions/standby.py @@ -451,8 +451,8 @@ class TestStandbyExtension(test_base.BaseTestCase): @mock.patch('ironic_python_agent.utils.execute', autospec=True) def test_run_image(self, execute_mock): - script = standby._path_to_script('shell/reboot.sh') - command = ['/bin/bash', script] + script = standby._path_to_script('shell/shutdown.sh') + command = ['/bin/bash', script, '-r'] execute_mock.return_value = ('', '') success_result = self.agent_extension.run_image() @@ -474,3 +474,25 @@ class TestStandbyExtension(test_base.BaseTestCase): def test_path_to_script(self): script = standby._path_to_script('shell/reboot.sh') self.assertTrue(script.endswith('extensions/../shell/reboot.sh')) + + @mock.patch('ironic_python_agent.utils.execute', autospec=True) + def test_power_off(self, execute_mock): + script = standby._path_to_script('shell/shutdown.sh') + command = ['/bin/bash', script, '-h'] + execute_mock.return_value = ('', '') + + success_result = self.agent_extension.power_off() + success_result.join() + + execute_mock.assert_called_once_with(*command, check_exit_code=[0]) + self.assertEqual('SUCCEEDED', success_result.command_status) + + execute_mock.reset_mock() + execute_mock.return_value = ('', '') + execute_mock.side_effect = processutils.ProcessExecutionError + + failed_result = self.agent_extension.power_off() + failed_result.join() + + execute_mock.assert_called_once_with(*command, check_exit_code=[0]) + self.assertEqual('FAILED', failed_result.command_status)