mirror of
https://github.com/krkn-chaos/krkn.git
synced 2026-08-25 09:27:36 +00:00
feat: Add exec_with_shell_fallback method and fix failing unit tests (#1225)
- Add exec_with_shell_fallback method with retry logic and shell fallback - Add unit tests for the new method with proper mocking - All tests now pass as expected Signed-off-by: NITESH SINGH <niteshkumar121411@gmail.com> Co-authored-by: Paige Patton <64206430+paigerube14@users.noreply.github.com>
This commit is contained in:
co-authored by
Paige Patton
parent
3b52fc4d5a
commit
53a81e8e90
@@ -77,6 +77,44 @@ class TimeActionsScenarioPlugin(AbstractScenarioPlugin):
|
||||
break
|
||||
return response
|
||||
|
||||
def exec_with_shell_fallback(self, command, pod_name, namespace, container_name, kubecli: KrknKubernetes, max_retries=3):
|
||||
"""
|
||||
Execute command in pod with shell fallback on failure.
|
||||
|
||||
Args:
|
||||
command: Command to execute (string or list)
|
||||
pod_name: Name of the pod
|
||||
namespace: Namespace of the pod
|
||||
container_name: Name of the container
|
||||
kubecli: Kubernetes client
|
||||
max_retries: Maximum number of retries
|
||||
|
||||
Returns:
|
||||
Command output or False on persistent failure
|
||||
"""
|
||||
# Try direct execution first
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
response = kubecli.exec_cmd_in_pod(command, pod_name, namespace, container_name)
|
||||
if response and not ("unauthorized" in response.lower() or "authorization" in response.lower()):
|
||||
return response
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# If direct execution fails, try with shell fallback
|
||||
try:
|
||||
shell_command = ["/bin/sh", "-c"] + (command if isinstance(command, list) else [command])
|
||||
response = kubecli.exec_cmd_in_pod(shell_command, pod_name, namespace, container_name)
|
||||
if response and not ("unauthorized" in response.lower() or "authorization" in response.lower()):
|
||||
return response
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if attempt < max_retries - 1:
|
||||
time.sleep(1)
|
||||
|
||||
return False
|
||||
|
||||
# krkn_lib
|
||||
def get_container_name(
|
||||
self, pod_name, namespace, kubecli: KrknKubernetes, container_name=""
|
||||
|
||||
@@ -121,6 +121,50 @@ class TestTimeActionsScenarioPlugin(unittest.TestCase):
|
||||
# Assert failure is returned
|
||||
self.assertEqual(result, 1)
|
||||
|
||||
@patch('krkn.scenario_plugins.time_actions.time_actions_scenario_plugin.KrknKubernetes')
|
||||
def test_exec_with_shell_fallback_detects_persistent_shell_error(self, mock_kubecli_class):
|
||||
"""Test that exec_with_shell_fallback returns False when both direct and shell execution fail persistently"""
|
||||
mock_kubecli = MagicMock()
|
||||
mock_kubecli_class.return_value = mock_kubecli
|
||||
mock_kubecli.exec_cmd_in_pod.side_effect = Exception("Command failed")
|
||||
|
||||
result = self.plugin.exec_with_shell_fallback(
|
||||
"test", "test-pod", "default", "test-container", mock_kubecli
|
||||
)
|
||||
|
||||
self.assertFalse(result)
|
||||
|
||||
@patch('krkn.scenario_plugins.time_actions.time_actions_scenario_plugin.KrknKubernetes')
|
||||
def test_exec_with_shell_fallback_fails_after_max_retries(self, mock_kubecli_class):
|
||||
"""Test that exec_with_shell_fallback returns False after exhausting all retries"""
|
||||
mock_kubecli = MagicMock()
|
||||
mock_kubecli_class.return_value = mock_kubecli
|
||||
mock_kubecli.exec_cmd_in_pod.side_effect = Exception("Command failed")
|
||||
|
||||
result = self.plugin.exec_with_shell_fallback(
|
||||
"test", "test-pod", "default", "test-container", mock_kubecli, max_retries=2
|
||||
)
|
||||
|
||||
self.assertFalse(result)
|
||||
|
||||
@patch('krkn.scenario_plugins.time_actions.time_actions_scenario_plugin.KrknKubernetes')
|
||||
def test_exec_with_shell_fallback_retries_on_error(self, mock_kubecli_class):
|
||||
"""Test that exec_with_shell_fallback succeeds after retrying"""
|
||||
mock_kubecli = MagicMock()
|
||||
mock_kubecli_class.return_value = mock_kubecli
|
||||
# First two calls fail, third succeeds
|
||||
mock_kubecli.exec_cmd_in_pod.side_effect = [
|
||||
Exception("First failure"),
|
||||
Exception("Second failure"),
|
||||
"success"
|
||||
]
|
||||
|
||||
result = self.plugin.exec_with_shell_fallback(
|
||||
"test", "test-pod", "default", "test-container", mock_kubecli, max_retries=3
|
||||
)
|
||||
|
||||
self.assertEqual(result, "success")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user