]> git.proxmox.com Git - ceph.git/blame - ceph/src/pybind/mgr/cephadm/tests/fixtures.py
import quincy beta 17.1.0
[ceph.git] / ceph / src / pybind / mgr / cephadm / tests / fixtures.py
CommitLineData
9f95a23c 1import fnmatch
20effc67
TL
2import asyncio
3import sys
4from tempfile import NamedTemporaryFile
f6b5b4d7
TL
5from contextlib import contextmanager
6
7from ceph.deployment.service_spec import PlacementSpec, ServiceSpec
adb31ebb 8from ceph.utils import datetime_to_str, datetime_now
20effc67 9from cephadm.serve import CephadmServe, cephadmNoImage
f6b5b4d7 10
9f95a23c 11try:
20effc67 12 from typing import Any, Iterator, List, Callable, Dict
9f95a23c
TL
13except ImportError:
14 pass
9f95a23c
TL
15
16from cephadm import CephadmOrchestrator
20effc67 17from orchestrator import raise_if_exception, OrchResult, HostSpec, DaemonDescriptionStatus
9f95a23c
TL
18from tests import mock
19
20
20effc67
TL
21def async_side_effect(result):
22 async def side_effect(*args, **kwargs):
23 return result
24 return side_effect
25
26
9f95a23c
TL
27def get_ceph_option(_, key):
28 return __file__
29
30
31def _run_cephadm(ret):
20effc67 32 async def foo(s, host, entity, cmd, e, **kwargs):
b3b6e05e
TL
33 if cmd == 'gather-facts':
34 return '{}', '', 0
f91f0fd5 35 return [ret], '', 0
9f95a23c
TL
36 return foo
37
38
39def match_glob(val, pat):
40 ok = fnmatch.fnmatchcase(val, pat)
41 if not ok:
42 assert pat in val
43
44
20effc67
TL
45class MockEventLoopThread:
46 def get_result(self, coro):
47 if sys.version_info >= (3, 7):
48 return asyncio.run(coro)
49
50 loop = asyncio.new_event_loop()
51 asyncio.set_event_loop(loop)
52 try:
53 return loop.run_until_complete(coro)
54 finally:
55 loop.close()
56 asyncio.set_event_loop(None)
57
58
59def receive_agent_metadata(m: CephadmOrchestrator, host: str, ops: List[str] = None) -> None:
60 to_update: Dict[str, Callable[[str, Any], None]] = {
61 'ls': m._process_ls_output,
62 'gather-facts': m.cache.update_host_facts,
63 'list-networks': m.cache.update_host_networks,
64 }
65 if ops:
66 for op in ops:
67 out = m.wait_async(CephadmServe(m)._run_cephadm_json(host, cephadmNoImage, op, []))
68 to_update[op](host, out)
69 m.cache.last_daemon_update[host] = datetime_now()
70 m.cache.last_facts_update[host] = datetime_now()
71 m.cache.last_network_update[host] = datetime_now()
72 m.cache.metadata_up_to_date[host] = True
73
74
75def receive_agent_metadata_all_hosts(m: CephadmOrchestrator) -> None:
76 for host in m.cache.get_hosts():
77 receive_agent_metadata(m, host)
78
79
f6b5b4d7
TL
80@contextmanager
81def with_cephadm_module(module_options=None, store=None):
82 """
83 :param module_options: Set opts as if they were set before module.__init__ is called
84 :param store: Set the store before module.__init__ is called
85 """
9f95a23c 86 with mock.patch("cephadm.module.CephadmOrchestrator.get_ceph_option", get_ceph_option),\
f6b5b4d7
TL
87 mock.patch("cephadm.services.osd.RemoveUtil._run_mon_cmd"), \
88 mock.patch("cephadm.module.CephadmOrchestrator.get_osdmap"), \
20effc67
TL
89 mock.patch("cephadm.module.CephadmOrchestrator.remote"), \
90 mock.patch("cephadm.agent.CephadmAgentHelpers._request_agent_acks"), \
91 mock.patch("cephadm.agent.CephadmAgentHelpers._apply_agent", return_value=False), \
92 mock.patch("cephadm.agent.CephadmAgentHelpers._agent_down", return_value=False), \
93 mock.patch('cephadm.agent.CherryPyThread.run'):
9f95a23c 94
f91f0fd5 95 m = CephadmOrchestrator.__new__(CephadmOrchestrator)
f6b5b4d7
TL
96 if module_options is not None:
97 for k, v in module_options.items():
98 m._ceph_set_module_option('cephadm', k, v)
99 if store is None:
100 store = {}
101 if '_ceph_get/mon_map' not in store:
102 m.mock_store_set('_ceph_get', 'mon_map', {
adb31ebb 103 'modified': datetime_to_str(datetime_now()),
f6b5b4d7
TL
104 'fsid': 'foobar',
105 })
a4b75251
TL
106 if '_ceph_get/mgr_map' not in store:
107 m.mock_store_set('_ceph_get', 'mgr_map', {
108 'services': {
109 'dashboard': 'http://[::1]:8080',
110 'prometheus': 'http://[::1]:8081'
111 },
112 'modules': ['dashboard', 'prometheus'],
113 })
f6b5b4d7
TL
114 for k, v in store.items():
115 m._ceph_set_store(k, v)
116
9f95a23c
TL
117 m.__init__('cephadm', 0, 0)
118 m._cluster_fsid = "fsid"
20effc67
TL
119
120 m.event_loop = MockEventLoopThread()
121 m.tkey = NamedTemporaryFile(prefix='test-cephadm-identity-')
122
9f95a23c
TL
123 yield m
124
125
126def wait(m, c):
f67539c2
TL
127 # type: (CephadmOrchestrator, OrchResult) -> Any
128 return raise_if_exception(c)
f6b5b4d7
TL
129
130
131@contextmanager
20effc67 132def with_host(m: CephadmOrchestrator, name, addr='1::4', refresh_hosts=True, rm_with_force=True):
b3b6e05e
TL
133 with mock.patch("cephadm.utils.resolve_ip", return_value=addr):
134 wait(m, m.add_host(HostSpec(hostname=name)))
135 if refresh_hosts:
136 CephadmServe(m)._refresh_hosts_and_daemons()
20effc67 137 receive_agent_metadata(m, name)
b3b6e05e 138 yield
20effc67 139 wait(m, m.remove_host(name, force=rm_with_force))
f6b5b4d7
TL
140
141
f67539c2
TL
142def assert_rm_service(cephadm: CephadmOrchestrator, srv_name):
143 mon_or_mgr = cephadm.spec_store[srv_name].spec.service_type in ('mon', 'mgr')
144 if mon_or_mgr:
145 assert 'Unable' in wait(cephadm, cephadm.remove_service(srv_name))
146 return
f6b5b4d7 147 assert wait(cephadm, cephadm.remove_service(srv_name)) == f'Removed service {srv_name}'
f67539c2
TL
148 assert cephadm.spec_store[srv_name].deleted is not None
149 CephadmServe(cephadm)._check_daemons()
f91f0fd5 150 CephadmServe(cephadm)._apply_all_services()
f67539c2
TL
151 assert cephadm.spec_store[srv_name].deleted
152 unmanaged = cephadm.spec_store[srv_name].spec.unmanaged
153 CephadmServe(cephadm)._purge_deleted_services()
154 if not unmanaged: # cause then we're not deleting daemons
155 assert srv_name not in cephadm.spec_store, f'{cephadm.spec_store[srv_name]!r}'
f6b5b4d7
TL
156
157
158@contextmanager
20effc67 159def with_service(cephadm_module: CephadmOrchestrator, spec: ServiceSpec, meth=None, host: str = '', status_running=False) -> Iterator[List[str]]:
f67539c2 160 if spec.placement.is_empty() and host:
f6b5b4d7 161 spec.placement = PlacementSpec(hosts=[host], count=1)
f67539c2
TL
162 if meth is not None:
163 c = meth(cephadm_module, spec)
164 assert wait(cephadm_module, c) == f'Scheduled {spec.service_name()} update...'
165 else:
166 c = cephadm_module.apply([spec])
167 assert wait(cephadm_module, c) == [f'Scheduled {spec.service_name()} update...']
168
f6b5b4d7
TL
169 specs = [d.spec for d in wait(cephadm_module, cephadm_module.describe_service())]
170 assert spec in specs
171
f91f0fd5 172 CephadmServe(cephadm_module)._apply_all_services()
f6b5b4d7 173
20effc67
TL
174 if status_running:
175 make_daemons_running(cephadm_module, spec.service_name())
176
f6b5b4d7 177 dds = wait(cephadm_module, cephadm_module.list_daemons())
f91f0fd5 178 own_dds = [dd for dd in dds if dd.service_name() == spec.service_name()]
20effc67 179 if host and spec.service_type != 'osd':
f67539c2 180 assert own_dds
f6b5b4d7 181
f91f0fd5 182 yield [dd.name() for dd in own_dds]
f6b5b4d7 183
f91f0fd5 184 assert_rm_service(cephadm_module, spec.service_name())
f67539c2
TL
185
186
20effc67
TL
187def make_daemons_running(cephadm_module, service_name):
188 own_dds = cephadm_module.cache.get_daemons_by_service(service_name)
189 for dd in own_dds:
190 dd.status = DaemonDescriptionStatus.running # We're changing the reference