]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/orchestrator/tests/test_orchestrator.py
import quincy beta 17.1.0
[ceph.git] / ceph / src / pybind / mgr / orchestrator / tests / test_orchestrator.py
1
2 import json
3 import textwrap
4
5 import pytest
6 import yaml
7
8 from ceph.deployment.service_spec import ServiceSpec
9 from ceph.deployment import inventory
10 from ceph.utils import datetime_now
11 from mgr_module import HandleCommandResult
12
13 from test_orchestrator import TestOrchestrator as _TestOrchestrator
14
15 from orchestrator import InventoryHost, DaemonDescription, ServiceDescription, DaemonDescriptionStatus, OrchResult
16 from orchestrator import OrchestratorValidationError
17 from orchestrator.module import to_format, Format, OrchestratorCli, preview_table_osd
18 from unittest import mock
19
20
21 def _test_resource(data, resource_class, extra=None):
22 # ensure we can deserialize and serialize
23 rsc = resource_class.from_json(data)
24 assert rsc.to_json() == resource_class.from_json(rsc.to_json()).to_json()
25
26 if extra:
27 # if there is an unexpected data provided
28 data_copy = data.copy()
29 data_copy.update(extra)
30 with pytest.raises(OrchestratorValidationError):
31 resource_class.from_json(data_copy)
32
33
34 def test_inventory():
35 json_data = {
36 'name': 'host0',
37 'addr': '1.2.3.4',
38 'devices': [
39 {
40 'sys_api': {
41 'rotational': '1',
42 'size': 1024,
43 },
44 'path': '/dev/sda',
45 'available': False,
46 'rejected_reasons': [],
47 'lvs': []
48 }
49 ]
50 }
51 _test_resource(json_data, InventoryHost, {'abc': False})
52 for devices in json_data['devices']:
53 _test_resource(devices, inventory.Device)
54
55 json_data = [{}, {'name': 'host0', 'addr': '1.2.3.4'}, {'devices': []}]
56 for data in json_data:
57 with pytest.raises(OrchestratorValidationError):
58 InventoryHost.from_json(data)
59
60
61 def test_daemon_description():
62 json_data = {
63 'hostname': 'test',
64 'daemon_type': 'mon',
65 'daemon_id': 'a',
66 'status': -1,
67 }
68 _test_resource(json_data, DaemonDescription, {'abc': False})
69
70 dd = DaemonDescription.from_json(json_data)
71 assert dd.status.value == DaemonDescriptionStatus.error.value
72
73
74 def test_apply():
75 to = _TestOrchestrator('', 0, 0)
76 completion = to.apply([
77 ServiceSpec(service_type='nfs', service_id='foo'),
78 ServiceSpec(service_type='nfs', service_id='foo'),
79 ServiceSpec(service_type='nfs', service_id='foo'),
80 ])
81 res = '<NFSServiceSpec for service_name=nfs.foo>'
82 assert completion.result == [res, res, res]
83
84
85 def test_yaml():
86 y = """daemon_type: crash
87 daemon_id: ubuntu
88 daemon_name: crash.ubuntu
89 hostname: ubuntu
90 status: 1
91 status_desc: starting
92 is_active: false
93 events:
94 - 2020-06-10T10:08:22.933241Z daemon:crash.ubuntu [INFO] "Deployed crash.ubuntu on
95 host 'ubuntu'"
96 ---
97 service_type: crash
98 service_name: crash
99 placement:
100 host_pattern: '*'
101 status:
102 container_image_id: 74803e884bea289d2d2d3ebdf6d37cd560499e955595695b1390a89800f4e37a
103 container_image_name: docker.io/ceph/daemon-base:latest-master-devel
104 created: '2020-06-10T10:37:31.051288Z'
105 last_refresh: '2020-06-10T10:57:40.715637Z'
106 running: 1
107 size: 1
108 events:
109 - 2020-06-10T10:37:31.139159Z service:crash [INFO] "service was created"
110 """
111 types = (DaemonDescription, ServiceDescription)
112
113 for y, cls in zip(y.split('---\n'), types):
114 data = yaml.safe_load(y)
115 object = cls.from_json(data)
116
117 assert to_format(object, Format.yaml, False, cls) == y
118 assert to_format([object], Format.yaml, True, cls) == y
119
120 j = json.loads(to_format(object, Format.json, False, cls))
121 assert to_format(cls.from_json(j), Format.yaml, False, cls) == y
122
123
124 def test_event_multiline():
125 from .._interface import OrchestratorEvent
126 e = OrchestratorEvent(datetime_now(), 'service', 'subject', 'ERROR', 'message')
127 assert OrchestratorEvent.from_json(e.to_json()) == e
128
129 e = OrchestratorEvent(datetime_now(), 'service',
130 'subject', 'ERROR', 'multiline\nmessage')
131 assert OrchestratorEvent.from_json(e.to_json()) == e
132
133
134 def test_handle_command():
135 cmd = {
136 'prefix': 'orch daemon add',
137 'daemon_type': 'mon',
138 'placement': 'smithi044:[v2:172.21.15.44:3301,v1:172.21.15.44:6790]=c',
139 }
140 m = OrchestratorCli('orchestrator', 0, 0)
141 r = m._handle_command(None, cmd)
142 assert r == HandleCommandResult(
143 retval=-2, stdout='', stderr='No orchestrator configured (try `ceph orch set backend`)')
144
145
146 r = OrchResult([ServiceDescription(spec=ServiceSpec(service_type='osd'), running=123)])
147
148
149 @mock.patch("orchestrator.OrchestratorCli.describe_service", return_value=r)
150 def test_orch_ls(_describe_service):
151 cmd = {
152 'prefix': 'orch ls',
153 }
154 m = OrchestratorCli('orchestrator', 0, 0)
155 r = m._handle_command(None, cmd)
156 out = 'NAME PORTS RUNNING REFRESHED AGE PLACEMENT \n' \
157 'osd 123 - - '
158 assert r == HandleCommandResult(retval=0, stdout=out, stderr='')
159
160 cmd = {
161 'prefix': 'orch ls',
162 'format': 'yaml',
163 }
164 m = OrchestratorCli('orchestrator', 0, 0)
165 r = m._handle_command(None, cmd)
166 out = textwrap.dedent("""
167 service_type: osd
168 service_name: osd
169 spec:
170 filter_logic: AND
171 objectstore: bluestore
172 status:
173 running: 123
174 size: 0
175 """).lstrip()
176 assert r == HandleCommandResult(retval=0, stdout=out, stderr='')
177
178
179 def test_preview_table_osd_smoke():
180 data = [
181 {
182 'service_type': 'osd',
183 'data':
184 {
185 'foo host':
186 [
187 {
188 'osdspec': 'foo',
189 'error': '',
190 'data':
191 [
192 {
193 "block_db": "/dev/nvme0n1",
194 "block_db_size": "66.67 GB",
195 "data": "/dev/sdb",
196 "data_size": "300.00 GB",
197 "encryption": "None"
198 },
199 {
200 "block_db": "/dev/nvme0n1",
201 "block_db_size": "66.67 GB",
202 "data": "/dev/sdc",
203 "data_size": "300.00 GB",
204 "encryption": "None"
205 },
206 {
207 "block_db": "/dev/nvme0n1",
208 "block_db_size": "66.67 GB",
209 "data": "/dev/sdd",
210 "data_size": "300.00 GB",
211 "encryption": "None"
212 }
213 ]
214 }
215 ]
216 }
217 }
218 ]
219 preview_table_osd(data)