]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/cephadm/tests/test_spec.py
Import ceph 15.2.8
[ceph.git] / ceph / src / pybind / mgr / cephadm / tests / test_spec.py
1 # Disable autopep8 for this file:
2
3 # fmt: off
4
5 import json
6
7 import pytest
8
9 from ceph.deployment.service_spec import ServiceSpec, NFSServiceSpec, RGWSpec, \
10 IscsiServiceSpec, AlertManagerSpec, HostPlacementSpec, CustomContainerSpec
11
12 from orchestrator import DaemonDescription, OrchestratorError
13
14
15 @pytest.mark.parametrize(
16 "spec_json",
17 json.loads("""[
18 {
19 "placement": {
20 "count": 1
21 },
22 "service_type": "alertmanager"
23 },
24 {
25 "placement": {
26 "host_pattern": "*"
27 },
28 "service_type": "crash"
29 },
30 {
31 "placement": {
32 "count": 1
33 },
34 "service_type": "grafana"
35 },
36 {
37 "placement": {
38 "count": 2
39 },
40 "service_type": "mgr"
41 },
42 {
43 "placement": {
44 "count": 5
45 },
46 "service_type": "mon"
47 },
48 {
49 "placement": {
50 "host_pattern": "*"
51 },
52 "service_type": "node-exporter"
53 },
54 {
55 "placement": {
56 "count": 1
57 },
58 "service_type": "prometheus"
59 },
60 {
61 "placement": {
62 "hosts": [
63 {
64 "hostname": "ceph-001",
65 "network": "",
66 "name": ""
67 }
68 ]
69 },
70 "service_type": "rgw",
71 "service_id": "default-rgw-realm.eu-central-1.1",
72 "rgw_realm": "default-rgw-realm",
73 "rgw_zone": "eu-central-1",
74 "subcluster": "1"
75 },
76 {
77 "service_type": "osd",
78 "service_id": "osd_spec_default",
79 "placement": {
80 "host_pattern": "*"
81 },
82 "data_devices": {
83 "model": "MC-55-44-XZ"
84 },
85 "db_devices": {
86 "model": "SSD-123-foo"
87 },
88 "wal_devices": {
89 "model": "NVME-QQQQ-987"
90 }
91 }
92 ]
93 """)
94 )
95 def test_spec_octopus(spec_json):
96 # https://tracker.ceph.com/issues/44934
97 # Those are real user data from early octopus.
98 # Please do not modify those JSON values.
99
100 spec = ServiceSpec.from_json(spec_json)
101 # just some verification that we can sill read old octopus specs
102 def convert_to_old_style_json(j):
103 j_c = dict(j.copy())
104 j_c.pop('service_name', None)
105 if 'spec' in j_c:
106 spec = j_c.pop('spec')
107 j_c.update(spec)
108 if 'placement' in j_c:
109 if 'hosts' in j_c['placement']:
110 j_c['placement']['hosts'] = [
111 {
112 'hostname': HostPlacementSpec.parse(h).hostname,
113 'network': HostPlacementSpec.parse(h).network,
114 'name': HostPlacementSpec.parse(h).name
115 }
116 for h in j_c['placement']['hosts']
117 ]
118 j_c.pop('objectstore', None)
119 j_c.pop('filter_logic', None)
120 return j_c
121 assert spec_json == convert_to_old_style_json(spec.to_json())
122
123
124 @pytest.mark.parametrize(
125 "dd_json",
126 json.loads("""[
127 {
128 "hostname": "ceph-001",
129 "container_id": "d94d7969094d",
130 "container_image_id": "0881eb8f169f5556a292b4e2c01d683172b12830a62a9225a98a8e206bb734f0",
131 "container_image_name": "docker.io/prom/alertmanager:latest",
132 "daemon_id": "ceph-001",
133 "daemon_type": "alertmanager",
134 "version": "0.20.0",
135 "status": 1,
136 "status_desc": "running",
137 "last_refresh": "2020-04-03T15:31:48.725856",
138 "created": "2020-04-02T19:23:08.829543",
139 "started": "2020-04-03T07:29:16.932838",
140 "is_active": false
141 },
142 {
143 "hostname": "ceph-001",
144 "container_id": "c4b036202241",
145 "container_image_id": "204a01f9b0b6710dd0c0af7f37ce7139c47ff0f0105d778d7104c69282dfbbf1",
146 "container_image_name": "docker.io/ceph/ceph:v15",
147 "daemon_id": "ceph-001",
148 "daemon_type": "crash",
149 "version": "15.2.0",
150 "status": 1,
151 "status_desc": "running",
152 "last_refresh": "2020-04-03T15:31:48.725903",
153 "created": "2020-04-02T19:23:11.390694",
154 "started": "2020-04-03T07:29:16.910897",
155 "is_active": false
156 },
157 {
158 "hostname": "ceph-001",
159 "container_id": "5b7b94b48f31",
160 "container_image_id": "87a51ecf0b1c9a7b187b21c1b071425dafea0d765a96d5bc371c791169b3d7f4",
161 "container_image_name": "docker.io/ceph/ceph-grafana:latest",
162 "daemon_id": "ceph-001",
163 "daemon_type": "grafana",
164 "version": "6.6.2",
165 "status": 1,
166 "status_desc": "running",
167 "last_refresh": "2020-04-03T15:31:48.725950",
168 "created": "2020-04-02T19:23:52.025088",
169 "started": "2020-04-03T07:29:16.847972",
170 "is_active": false
171 },
172 {
173 "hostname": "ceph-001",
174 "container_id": "9ca007280456",
175 "container_image_id": "204a01f9b0b6710dd0c0af7f37ce7139c47ff0f0105d778d7104c69282dfbbf1",
176 "container_image_name": "docker.io/ceph/ceph:v15",
177 "daemon_id": "ceph-001.gkjwqp",
178 "daemon_type": "mgr",
179 "version": "15.2.0",
180 "status": 1,
181 "status_desc": "running",
182 "last_refresh": "2020-04-03T15:31:48.725807",
183 "created": "2020-04-02T19:22:18.648584",
184 "started": "2020-04-03T07:29:16.856153",
185 "is_active": false
186 },
187 {
188 "hostname": "ceph-001",
189 "container_id": "3d1ba9a2b697",
190 "container_image_id": "204a01f9b0b6710dd0c0af7f37ce7139c47ff0f0105d778d7104c69282dfbbf1",
191 "container_image_name": "docker.io/ceph/ceph:v15",
192 "daemon_id": "ceph-001",
193 "daemon_type": "mon",
194 "version": "15.2.0",
195 "status": 1,
196 "status_desc": "running",
197 "last_refresh": "2020-04-03T15:31:48.725715",
198 "created": "2020-04-02T19:22:13.863300",
199 "started": "2020-04-03T07:29:17.206024",
200 "is_active": false
201 },
202 {
203 "hostname": "ceph-001",
204 "container_id": "36d026c68ba1",
205 "container_image_id": "e5a616e4b9cf68dfcad7782b78e118be4310022e874d52da85c55923fb615f87",
206 "container_image_name": "docker.io/prom/node-exporter:latest",
207 "daemon_id": "ceph-001",
208 "daemon_type": "node-exporter",
209 "version": "0.18.1",
210 "status": 1,
211 "status_desc": "running",
212 "last_refresh": "2020-04-03T15:31:48.725996",
213 "created": "2020-04-02T19:23:53.880197",
214 "started": "2020-04-03T07:29:16.880044",
215 "is_active": false
216 },
217 {
218 "hostname": "ceph-001",
219 "container_id": "faf76193cbfe",
220 "container_image_id": "204a01f9b0b6710dd0c0af7f37ce7139c47ff0f0105d778d7104c69282dfbbf1",
221 "container_image_name": "docker.io/ceph/ceph:v15",
222 "daemon_id": "0",
223 "daemon_type": "osd",
224 "version": "15.2.0",
225 "status": 1,
226 "status_desc": "running",
227 "last_refresh": "2020-04-03T15:31:48.726088",
228 "created": "2020-04-02T20:35:02.991435",
229 "started": "2020-04-03T07:29:19.373956",
230 "is_active": false
231 },
232 {
233 "hostname": "ceph-001",
234 "container_id": "f82505bae0f1",
235 "container_image_id": "204a01f9b0b6710dd0c0af7f37ce7139c47ff0f0105d778d7104c69282dfbbf1",
236 "container_image_name": "docker.io/ceph/ceph:v15",
237 "daemon_id": "1",
238 "daemon_type": "osd",
239 "version": "15.2.0",
240 "status": 1,
241 "status_desc": "running",
242 "last_refresh": "2020-04-03T15:31:48.726134",
243 "created": "2020-04-02T20:35:17.142272",
244 "started": "2020-04-03T07:29:19.374002",
245 "is_active": false
246 },
247 {
248 "hostname": "ceph-001",
249 "container_id": "2708d84cd484",
250 "container_image_id": "358a0d2395fe711bb8258e8fb4b2d7865c0a9a6463969bcd1452ee8869ea6653",
251 "container_image_name": "docker.io/prom/prometheus:latest",
252 "daemon_id": "ceph-001",
253 "daemon_type": "prometheus",
254 "version": "2.17.1",
255 "status": 1,
256 "status_desc": "running",
257 "last_refresh": "2020-04-03T15:31:48.726042",
258 "created": "2020-04-02T19:24:10.281163",
259 "started": "2020-04-03T07:29:16.926292",
260 "is_active": false
261 },
262 {
263 "hostname": "ceph-001",
264 "daemon_id": "default-rgw-realm.eu-central-1.1.ceph-001.ytywjo",
265 "daemon_type": "rgw",
266 "status": 1,
267 "status_desc": "starting",
268 "is_active": false
269 }
270 ]""")
271 )
272 def test_dd_octopus(dd_json):
273 # https://tracker.ceph.com/issues/44934
274 # Those are real user data from early octopus.
275 # Please do not modify those JSON values.
276 assert dd_json == DaemonDescription.from_json(dd_json).to_json()
277
278
279 @pytest.mark.parametrize("spec,dd,valid",
280 [
281 # https://tracker.ceph.com/issues/44934
282 (
283 RGWSpec(
284 rgw_realm="default-rgw-realm",
285 rgw_zone="eu-central-1",
286 subcluster='1',
287 ),
288 DaemonDescription(
289 daemon_type='rgw',
290 daemon_id="default-rgw-realm.eu-central-1.1.ceph-001.ytywjo",
291 hostname="ceph-001",
292 ),
293 True
294 ),
295 (
296 # no subcluster
297 RGWSpec(
298 rgw_realm="default-rgw-realm",
299 rgw_zone="eu-central-1",
300 ),
301 DaemonDescription(
302 daemon_type='rgw',
303 daemon_id="default-rgw-realm.eu-central-1.ceph-001.ytywjo",
304 hostname="ceph-001",
305 ),
306 True
307 ),
308 (
309 # with tld
310 RGWSpec(
311 rgw_realm="default-rgw-realm",
312 rgw_zone="eu-central-1",
313 subcluster='1',
314 ),
315 DaemonDescription(
316 daemon_type='rgw',
317 daemon_id="default-rgw-realm.eu-central-1.1.host.domain.tld.ytywjo",
318 hostname="host.domain.tld",
319 ),
320 True
321 ),
322 (
323 # explicit naming
324 RGWSpec(
325 rgw_realm="realm",
326 rgw_zone="zone",
327 ),
328 DaemonDescription(
329 daemon_type='rgw',
330 daemon_id="realm.zone.a",
331 hostname="smithi028",
332 ),
333 True
334 ),
335 (
336 # without host
337 RGWSpec(
338 service_type='rgw',
339 rgw_realm="default-rgw-realm",
340 rgw_zone="eu-central-1",
341 subcluster='1',
342 ),
343 DaemonDescription(
344 daemon_type='rgw',
345 daemon_id="default-rgw-realm.eu-central-1.1.hostname.ytywjo",
346 hostname=None,
347 ),
348 False
349 ),
350 (
351 # zone contains hostname
352 # https://tracker.ceph.com/issues/45294
353 RGWSpec(
354 rgw_realm="default.rgw.realm",
355 rgw_zone="ceph.001",
356 subcluster='1',
357 ),
358 DaemonDescription(
359 daemon_type='rgw',
360 daemon_id="default.rgw.realm.ceph.001.1.ceph.001.ytywjo",
361 hostname="ceph.001",
362 ),
363 True
364 ),
365
366 # https://tracker.ceph.com/issues/45293
367 (
368 ServiceSpec(
369 service_type='mds',
370 service_id="a",
371 ),
372 DaemonDescription(
373 daemon_type='mds',
374 daemon_id="a.host1.abc123",
375 hostname="host1",
376 ),
377 True
378 ),
379 (
380 # '.' char in service_id
381 ServiceSpec(
382 service_type='mds',
383 service_id="a.b.c",
384 ),
385 DaemonDescription(
386 daemon_type='mds',
387 daemon_id="a.b.c.host1.abc123",
388 hostname="host1",
389 ),
390 True
391 ),
392
393 # https://tracker.ceph.com/issues/45617
394 (
395 # daemon_id does not contain hostname
396 ServiceSpec(
397 service_type='mds',
398 service_id="a",
399 ),
400 DaemonDescription(
401 daemon_type='mds',
402 daemon_id="a",
403 hostname="host1",
404 ),
405 True
406 ),
407 (
408 # daemon_id only contains hostname
409 ServiceSpec(
410 service_type='mds',
411 service_id="host1",
412 ),
413 DaemonDescription(
414 daemon_type='mds',
415 daemon_id="host1",
416 hostname="host1",
417 ),
418 True
419 ),
420
421 # https://tracker.ceph.com/issues/45399
422 (
423 # daemon_id only contains hostname
424 ServiceSpec(
425 service_type='mds',
426 service_id="a",
427 ),
428 DaemonDescription(
429 daemon_type='mds',
430 daemon_id="a.host1.abc123",
431 hostname="host1.site",
432 ),
433 True
434 ),
435 (
436 NFSServiceSpec(
437 service_id="a",
438 ),
439 DaemonDescription(
440 daemon_type='nfs',
441 daemon_id="a.host1",
442 hostname="host1.site",
443 ),
444 True
445 ),
446
447 # https://tracker.ceph.com/issues/45293
448 (
449 NFSServiceSpec(
450 service_id="a",
451 ),
452 DaemonDescription(
453 daemon_type='nfs',
454 daemon_id="a.host1",
455 hostname="host1",
456 ),
457 True
458 ),
459 (
460 # service_id contains a '.' char
461 NFSServiceSpec(
462 service_id="a.b.c",
463 ),
464 DaemonDescription(
465 daemon_type='nfs',
466 daemon_id="a.b.c.host1",
467 hostname="host1",
468 ),
469 True
470 ),
471 (
472 # trailing chars after hostname
473 NFSServiceSpec(
474 service_id="a.b.c",
475 ),
476 DaemonDescription(
477 daemon_type='nfs',
478 daemon_id="a.b.c.host1.abc123",
479 hostname="host1",
480 ),
481 True
482 ),
483 (
484 # chars after hostname without '.'
485 NFSServiceSpec(
486 service_id="a",
487 ),
488 DaemonDescription(
489 daemon_type='nfs',
490 daemon_id="a.host1abc123",
491 hostname="host1",
492 ),
493 False
494 ),
495 (
496 # chars before hostname without '.'
497 NFSServiceSpec(
498 service_id="a",
499 ),
500 DaemonDescription(
501 daemon_type='nfs',
502 daemon_id="ahost1.abc123",
503 hostname="host1",
504 ),
505 False
506 ),
507
508 # https://tracker.ceph.com/issues/45293
509 (
510 IscsiServiceSpec(
511 service_type='iscsi',
512 service_id="a",
513 ),
514 DaemonDescription(
515 daemon_type='iscsi',
516 daemon_id="a.host1.abc123",
517 hostname="host1",
518 ),
519 True
520 ),
521 (
522 # '.' char in service_id
523 IscsiServiceSpec(
524 service_type='iscsi',
525 service_id="a.b.c",
526 ),
527 DaemonDescription(
528 daemon_type='iscsi',
529 daemon_id="a.b.c.host1.abc123",
530 hostname="host1",
531 ),
532 True
533 ),
534 (
535 # fixed daemon id for teuthology.
536 IscsiServiceSpec(
537 service_type='iscsi',
538 service_id='iscsi',
539 ),
540 DaemonDescription(
541 daemon_type='iscsi',
542 daemon_id="iscsi.a",
543 hostname="host1",
544 ),
545 True
546 ),
547
548 (
549 CustomContainerSpec(
550 service_type='container',
551 service_id='hello-world',
552 image='docker.io/library/hello-world:latest',
553 ),
554 DaemonDescription(
555 daemon_type='container',
556 daemon_id='hello-world.mgr0',
557 hostname='mgr0',
558 ),
559 True
560 ),
561 ])
562 def test_daemon_description_service_name(spec: ServiceSpec,
563 dd: DaemonDescription,
564 valid: bool):
565 if valid:
566 assert spec.service_name() == dd.service_name()
567 else:
568 with pytest.raises(OrchestratorError):
569 dd.service_name()
570
571
572 def test_alertmanager_spec_1():
573 spec = AlertManagerSpec()
574 assert spec.service_type == 'alertmanager'
575 assert isinstance(spec.user_data, dict)
576 assert len(spec.user_data.keys()) == 0
577
578
579 def test_alertmanager_spec_2():
580 spec = AlertManagerSpec(user_data={'default_webhook_urls': ['foo']})
581 assert isinstance(spec.user_data, dict)
582 assert 'default_webhook_urls' in spec.user_data.keys()
583
584
585 def test_custom_container_spec():
586 spec = CustomContainerSpec(service_id='hello-world',
587 image='docker.io/library/hello-world:latest',
588 entrypoint='/usr/bin/bash',
589 uid=1000,
590 gid=2000,
591 volume_mounts={'foo': '/foo'},
592 args=['--foo'],
593 envs=['FOO=0815'],
594 bind_mounts=[
595 [
596 'type=bind',
597 'source=lib/modules',
598 'destination=/lib/modules',
599 'ro=true'
600 ]
601 ],
602 ports=[8080, 8443],
603 dirs=['foo', 'bar'],
604 files={
605 'foo.conf': 'foo\nbar',
606 'bar.conf': ['foo', 'bar']
607 })
608 assert spec.service_type == 'container'
609 assert spec.entrypoint == '/usr/bin/bash'
610 assert spec.uid == 1000
611 assert spec.gid == 2000
612 assert spec.volume_mounts == {'foo': '/foo'}
613 assert spec.args == ['--foo']
614 assert spec.envs == ['FOO=0815']
615 assert spec.bind_mounts == [
616 [
617 'type=bind',
618 'source=lib/modules',
619 'destination=/lib/modules',
620 'ro=true'
621 ]
622 ]
623 assert spec.ports == [8080, 8443]
624 assert spec.dirs == ['foo', 'bar']
625 assert spec.files == {
626 'foo.conf': 'foo\nbar',
627 'bar.conf': ['foo', 'bar']
628 }
629
630
631 def test_custom_container_spec_config_json():
632 spec = CustomContainerSpec(service_id='foo', image='foo', dirs=None)
633 config_json = spec.config_json()
634 for key in ['entrypoint', 'uid', 'gid', 'bind_mounts', 'dirs']:
635 assert key not in config_json