]>
git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/cephadm/tests/test_ssh.py
2 from asyncssh
.process
import SSHCompletedProcess
3 from unittest
import mock
5 # AsyncMock was not added until python 3.8
6 from unittest
.mock
import AsyncMock
8 from asyncmock
import AsyncMock
15 from asyncssh
.misc
import ConnectionLost
19 from ceph
.deployment
.hostspec
import HostSpec
21 from cephadm
import CephadmOrchestrator
22 from cephadm
.serve
import CephadmServe
23 from cephadm
.tests
.fixtures
import with_host
, wait
, async_side_effect
24 from orchestrator
import OrchestratorError
27 @pytest.mark
.skipif(ConnectionLost
is None, reason
='no asyncssh')
29 @mock.patch("cephadm.ssh.SSHManager._execute_command")
30 @mock.patch("cephadm.ssh.SSHManager._check_execute_command")
31 def test_offline(self
, check_execute_command
, execute_command
, cephadm_module
):
32 check_execute_command
.side_effect
= async_side_effect('')
33 execute_command
.side_effect
= async_side_effect(('', '', 0))
36 # can't run this test if we could not import AsyncMock
38 mock_connect
= AsyncMock(return_value
='')
39 with mock
.patch("asyncssh.connect", new
=mock_connect
) as asyncssh_connect
:
40 with
with_host(cephadm_module
, 'test'):
41 asyncssh_connect
.side_effect
= ConnectionLost('reason')
42 code
, out
, err
= cephadm_module
.check_host('test')
44 assert "Failed to connect to test at address (1::4)" in err
46 out
= wait(cephadm_module
, cephadm_module
.get_hosts())[0].to_json()
47 assert out
== HostSpec('test', '1::4', status
='Offline').to_json()
49 asyncssh_connect
.return_value
= mock
.MagicMock()
50 asyncssh_connect
.side_effect
= None
51 assert CephadmServe(cephadm_module
)._check
_host
('test') is None
52 out
= wait(cephadm_module
, cephadm_module
.get_hosts())[0].to_json()
53 assert out
== HostSpec('test', '1::4').to_json()
55 def test_ssh_remote_cmds_execution(self
, cephadm_module
):
58 # can't run this test if we could not import AsyncMock
62 def __init__(self
, exception
=None, returncode
=0):
63 self
.exception
= exception
64 self
.returncode
= returncode
66 async def run(self
, *args
, **kwargs
):
70 return SSHCompletedProcess(returncode
=self
.returncode
, stdout
="", stderr
="")
72 async def close(self
):
75 def run_test(host
, conn
, expected_error
):
76 mock_connect
= AsyncMock(return_value
=conn
)
77 with pytest
.raises(OrchestratorError
, match
=expected_error
):
78 with mock
.patch("asyncssh.connect", new
=mock_connect
):
79 with
with_host(cephadm_module
, host
):
80 CephadmServe(cephadm_module
)._check
_host
(host
)
82 # Test case 1: command failure
83 run_test('test1', FakeConn(returncode
=1), "Command .+ failed")
85 # Test case 2: connection error
86 run_test('test2', FakeConn(exception
=asyncssh
.ChannelOpenError(1, "", "")), "Unable to reach remote host test2.")
88 # Test case 3: asyncssh ProcessError
89 stderr
= "my-process-stderr"
90 run_test('test3', FakeConn(exception
=asyncssh
.ProcessError(returncode
=3,
97 stdout
="")), f
"Cannot execute the command.+{stderr}")
98 # Test case 4: generic error
99 run_test('test4', FakeConn(exception
=Exception), "Generic error while executing command.+")
102 @pytest.mark
.skipif(ConnectionLost
is not None, reason
='asyncssh')
103 class TestWithoutSSH
:
104 def test_can_run(self
, cephadm_module
: CephadmOrchestrator
):
105 assert cephadm_module
.can_run() == (False, "loading asyncssh library:No module named 'asyncssh'")