]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/cephadm/tests/test_osd_removal.py
import 15.2.5
[ceph.git] / ceph / src / pybind / mgr / cephadm / tests / test_osd_removal.py
1 from cephadm.services.osd import RemoveUtil, OSDQueue, OSD
2 import pytest
3 from .fixtures import rm_util, osd_obj
4 from tests import mock
5 from datetime import datetime
6
7
8 class MockOSD:
9
10 def __init__(self, osd_id):
11 self.osd_id = osd_id
12
13 class TestOSDRemoval:
14
15 @pytest.mark.parametrize(
16 "osd_id, osd_df, expected",
17 [
18 # missing 'nodes' key
19 (1, dict(nodes=[]), -1),
20 # missing 'pgs' key
21 (1, dict(nodes=[dict(id=1)]), -1),
22 # id != osd_id
23 (1, dict(nodes=[dict(id=999, pgs=1)]), -1),
24 # valid
25 (1, dict(nodes=[dict(id=1, pgs=1)]), 1),
26 ]
27 )
28 def test_get_pg_count(self, rm_util, osd_id, osd_df, expected):
29 with mock.patch("cephadm.services.osd.RemoveUtil.osd_df", return_value=osd_df):
30 assert rm_util.get_pg_count(osd_id) == expected
31
32 @pytest.mark.parametrize(
33 "osds, ok_to_stop, expected",
34 [
35 # no osd_ids provided
36 ([], [False], []),
37 # all osds are ok_to_stop
38 ([1, 2], [True], [1, 2]),
39 # osds are ok_to_stop after the second iteration
40 ([1, 2], [False, True], [2]),
41 # osds are never ok_to_stop, (taking the sample size `(len(osd_ids))` into account),
42 # expected to get False
43 ([1, 2], [False, False], []),
44 ]
45 )
46 def test_find_stop_threshold(self, rm_util, osds, ok_to_stop, expected):
47 with mock.patch("cephadm.services.osd.RemoveUtil.ok_to_stop", side_effect=ok_to_stop):
48 assert rm_util.find_osd_stop_threshold(osds) == expected
49
50 def test_process_removal_queue(self, rm_util):
51 # TODO: !
52 # rm_util.process_removal_queue()
53 pass
54
55 def test_ok_to_stop(self, rm_util):
56 rm_util.ok_to_stop([MockOSD(1)])
57 rm_util._run_mon_cmd.assert_called_with({'prefix': 'osd ok-to-stop', 'ids': ['1']})
58
59 def test_safe_to_destroy(self, rm_util):
60 rm_util.safe_to_destroy([1])
61 rm_util._run_mon_cmd.assert_called_with({'prefix': 'osd safe-to-destroy', 'ids': ['1']})
62
63 def test_destroy_osd(self, rm_util):
64 rm_util.destroy_osd(1)
65 rm_util._run_mon_cmd.assert_called_with({'prefix': 'osd destroy-actual', 'id': 1, 'yes_i_really_mean_it': True})
66
67 def test_purge_osd(self, rm_util):
68 rm_util.purge_osd(1)
69 rm_util._run_mon_cmd.assert_called_with({'prefix': 'osd purge-actual', 'id': 1, 'yes_i_really_mean_it': True})
70
71
72 class TestOSD:
73
74 def test_start(self, osd_obj):
75 assert osd_obj.started is False
76 osd_obj.start()
77 assert osd_obj.started is True
78 assert osd_obj.stopped is False
79
80 def test_start_draining(self, osd_obj):
81 assert osd_obj.draining is False
82 assert osd_obj.drain_started_at is None
83 ret = osd_obj.start_draining()
84 osd_obj.rm_util.set_osd_flag.assert_called_with([osd_obj], 'out')
85 assert isinstance(osd_obj.drain_started_at, datetime)
86 assert osd_obj.draining is True
87 assert ret is True
88
89 def test_start_draining_stopped(self, osd_obj):
90 osd_obj.stopped = True
91 ret = osd_obj.start_draining()
92 assert osd_obj.drain_started_at is None
93 assert ret is False
94 assert osd_obj.draining is False
95
96 def test_stop_draining(self, osd_obj):
97 ret = osd_obj.stop_draining()
98 osd_obj.rm_util.set_osd_flag.assert_called_with([osd_obj], 'in')
99 assert isinstance(osd_obj.drain_stopped_at, datetime)
100 assert osd_obj.draining is False
101 assert ret is True
102
103 @mock.patch('cephadm.services.osd.OSD.stop_draining')
104 def test_stop(self, stop_draining_mock, osd_obj):
105 ret = osd_obj.stop()
106 assert osd_obj.started is False
107 assert osd_obj.stopped is True
108 stop_draining_mock.assert_called_once()
109
110 @pytest.mark.parametrize(
111 "draining, empty, expected",
112 [
113 # must be !draining! and !not empty! to yield True
114 (True, not True, True),
115 # not draining and not empty
116 (False, not True, False),
117 # not draining and empty
118 (False, True, False),
119 # draining and empty
120 (True, True, False),
121 ]
122 )
123 def test_is_draining(self, osd_obj, draining, empty, expected):
124 with mock.patch("cephadm.services.osd.OSD.is_empty", new_callable=mock.PropertyMock(return_value=empty)):
125 osd_obj.draining = draining
126 assert osd_obj.is_draining is expected
127
128 @mock.patch("cephadm.services.osd.RemoveUtil.ok_to_stop")
129 def test_is_ok_to_stop(self, _, osd_obj):
130 ret = osd_obj.is_ok_to_stop
131 osd_obj.rm_util.ok_to_stop.assert_called_once()
132
133 @pytest.mark.parametrize(
134 "pg_count, expected",
135 [
136 (0, True),
137 (1, False),
138 (9999, False),
139 (-1, False),
140 ]
141 )
142 def test_is_empty(self, osd_obj, pg_count, expected):
143 with mock.patch("cephadm.services.osd.OSD.get_pg_count", return_value=pg_count):
144 assert osd_obj.is_empty is expected
145
146 @mock.patch("cephadm.services.osd.RemoveUtil.safe_to_destroy")
147 def test_safe_to_destroy(self, _, osd_obj):
148 ret = osd_obj.safe_to_destroy()
149 osd_obj.rm_util.safe_to_destroy.assert_called_once()
150
151 @mock.patch("cephadm.services.osd.RemoveUtil.set_osd_flag")
152 def test_down(self, _, osd_obj):
153 ret = osd_obj.down()
154 osd_obj.rm_util.set_osd_flag.assert_called_with([osd_obj], 'down')
155
156 @mock.patch("cephadm.services.osd.RemoveUtil.destroy_osd")
157 def test_destroy_osd(self, _, osd_obj):
158 ret = osd_obj.destroy()
159 osd_obj.rm_util.destroy_osd.assert_called_once()
160
161 @mock.patch("cephadm.services.osd.RemoveUtil.purge_osd")
162 def test_purge(self, _, osd_obj):
163 ret = osd_obj.purge()
164 osd_obj.rm_util.purge_osd.assert_called_once()
165
166 @mock.patch("cephadm.services.osd.RemoveUtil.get_pg_count")
167 def test_pg_count(self, _, osd_obj):
168 ret = osd_obj.get_pg_count()
169 osd_obj.rm_util.get_pg_count.assert_called_once()
170
171 def test_drain_status_human_not_started(self, osd_obj):
172 assert osd_obj.drain_status_human() == 'not started'
173
174 def test_drain_status_human_started(self, osd_obj):
175 osd_obj.started = True
176 assert osd_obj.drain_status_human() == 'started'
177
178 def test_drain_status_human_draining(self, osd_obj):
179 osd_obj.started = True
180 osd_obj.draining = True
181 assert osd_obj.drain_status_human() == 'draining'
182
183 def test_drain_status_human_done(self, osd_obj):
184 osd_obj.started = True
185 osd_obj.draining = False
186 osd_obj.drain_done_at = datetime.utcnow()
187 assert osd_obj.drain_status_human() == 'done, waiting for purge'
188
189
190 class TestOSDQueue:
191
192 def test_queue_size(self, osd_obj):
193 q = OSDQueue()
194 assert q.queue_size() == 0
195 q.add(osd_obj)
196 assert q.queue_size() == 1
197
198 @mock.patch("cephadm.services.osd.OSD.start")
199 @mock.patch("cephadm.services.osd.OSD.exists")
200 def test_enqueue(self, exist, start, osd_obj):
201 q = OSDQueue()
202 q.enqueue(osd_obj)
203 osd_obj.start.assert_called_once()
204
205 @mock.patch("cephadm.services.osd.OSD.stop")
206 @mock.patch("cephadm.services.osd.OSD.exists")
207 def test_rm_raise(self, exist, stop, osd_obj):
208 q = OSDQueue()
209 with pytest.raises(KeyError):
210 q.rm(osd_obj)
211 osd_obj.stop.assert_called_once()
212
213 @mock.patch("cephadm.services.osd.OSD.stop")
214 @mock.patch("cephadm.services.osd.OSD.exists")
215 def test_rm(self, exist, stop, osd_obj):
216 q = OSDQueue()
217 q.add(osd_obj)
218 q.rm(osd_obj)
219 osd_obj.stop.assert_called_once()