]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/cephadm/services/cephadmservice.py
bump version to 15.2.4-pve1
[ceph.git] / ceph / src / pybind / mgr / cephadm / services / cephadmservice.py
1 import logging
2 from typing import TYPE_CHECKING, List
3
4 from mgr_module import MonCommandFailed
5
6 from ceph.deployment.service_spec import ServiceSpec, RGWSpec
7 from orchestrator import OrchestratorError, DaemonDescription
8 from cephadm import utils
9
10 if TYPE_CHECKING:
11 from cephadm.module import CephadmOrchestrator
12
13 logger = logging.getLogger(__name__)
14
15
16 class CephadmService:
17 """
18 Base class for service types. Often providing a create() and config() fn.
19 """
20 def __init__(self, mgr: "CephadmOrchestrator"):
21 self.mgr: "CephadmOrchestrator" = mgr
22
23 def daemon_check_post(self, daemon_descrs: List[DaemonDescription]):
24 """The post actions needed to be done after daemons are checked"""
25 raise NotImplementedError()
26
27 def get_active_daemon(self, daemon_descrs: List[DaemonDescription]) -> DaemonDescription:
28 raise NotImplementedError()
29
30 def _inventory_get_addr(self, hostname: str):
31 """Get a host's address with its hostname."""
32 return self.mgr.inventory.get_addr(hostname)
33
34 def _set_service_url_on_dashboard(self,
35 service_name: str,
36 get_mon_cmd: str,
37 set_mon_cmd: str,
38 service_url: str):
39 """A helper to get and set service_url via Dashboard's MON command."""
40 try:
41 _, out, _ = self.mgr.check_mon_command({
42 'prefix': get_mon_cmd
43 })
44 except MonCommandFailed as e:
45 logger.warning('Failed to get service URL for %s: %s', service_name, e)
46 return
47 if out.strip() != service_url:
48 try:
49 logger.info(
50 'Setting service URL %s for %s in the Dashboard', service_url, service_name)
51 _, out, _ = self.mgr.check_mon_command({
52 'prefix': set_mon_cmd,
53 'value': service_url,
54 })
55 except MonCommandFailed as e:
56 logger.warning('Failed to set service URL %s for %s in the Dashboard: %s',
57 service_url, service_name, e)
58
59
60 class MonService(CephadmService):
61 def create(self, name, host, network):
62 """
63 Create a new monitor on the given host.
64 """
65 # get mon. key
66 ret, keyring, err = self.mgr.check_mon_command({
67 'prefix': 'auth get',
68 'entity': 'mon.',
69 })
70
71 extra_config = '[mon.%s]\n' % name
72 if network:
73 # infer whether this is a CIDR network, addrvec, or plain IP
74 if '/' in network:
75 extra_config += 'public network = %s\n' % network
76 elif network.startswith('[v') and network.endswith(']'):
77 extra_config += 'public addrv = %s\n' % network
78 elif ':' not in network:
79 extra_config += 'public addr = %s\n' % network
80 else:
81 raise OrchestratorError('Must specify a CIDR network, ceph addrvec, or plain IP: \'%s\'' % network)
82 else:
83 # try to get the public_network from the config
84 ret, network, err = self.mgr.check_mon_command({
85 'prefix': 'config get',
86 'who': 'mon',
87 'key': 'public_network',
88 })
89 network = network.strip() # type: ignore
90 if not network:
91 raise OrchestratorError('Must set public_network config option or specify a CIDR network, ceph addrvec, or plain IP')
92 if '/' not in network:
93 raise OrchestratorError('public_network is set but does not look like a CIDR network: \'%s\'' % network)
94 extra_config += 'public network = %s\n' % network
95
96 return self.mgr._create_daemon('mon', name, host,
97 keyring=keyring,
98 extra_config={'config': extra_config})
99
100
101 class MgrService(CephadmService):
102 def create(self, mgr_id, host):
103 """
104 Create a new manager instance on a host.
105 """
106 # get mgr. key
107 ret, keyring, err = self.mgr.check_mon_command({
108 'prefix': 'auth get-or-create',
109 'entity': 'mgr.%s' % mgr_id,
110 'caps': ['mon', 'profile mgr',
111 'osd', 'allow *',
112 'mds', 'allow *'],
113 })
114
115 return self.mgr._create_daemon('mgr', mgr_id, host, keyring=keyring)
116
117
118 class MdsService(CephadmService):
119 def config(self, spec: ServiceSpec):
120 # ensure mds_join_fs is set for these daemons
121 assert spec.service_id
122 ret, out, err = self.mgr.check_mon_command({
123 'prefix': 'config set',
124 'who': 'mds.' + spec.service_id,
125 'name': 'mds_join_fs',
126 'value': spec.service_id,
127 })
128
129 def create(self, mds_id, host) -> str:
130 # get mgr. key
131 ret, keyring, err = self.mgr.check_mon_command({
132 'prefix': 'auth get-or-create',
133 'entity': 'mds.' + mds_id,
134 'caps': ['mon', 'profile mds',
135 'osd', 'allow rwx',
136 'mds', 'allow'],
137 })
138 return self.mgr._create_daemon('mds', mds_id, host, keyring=keyring)
139
140
141 class RgwService(CephadmService):
142 def config(self, spec: RGWSpec):
143 # ensure rgw_realm and rgw_zone is set for these daemons
144 ret, out, err = self.mgr.check_mon_command({
145 'prefix': 'config set',
146 'who': f"{utils.name_to_config_section('rgw')}.{spec.service_id}",
147 'name': 'rgw_zone',
148 'value': spec.rgw_zone,
149 })
150 ret, out, err = self.mgr.check_mon_command({
151 'prefix': 'config set',
152 'who': f"{utils.name_to_config_section('rgw')}.{spec.rgw_realm}",
153 'name': 'rgw_realm',
154 'value': spec.rgw_realm,
155 })
156 ret, out, err = self.mgr.check_mon_command({
157 'prefix': 'config set',
158 'who': f"{utils.name_to_config_section('rgw')}.{spec.service_id}",
159 'name': 'rgw_frontends',
160 'value': spec.rgw_frontends_config_value(),
161 })
162
163 if spec.rgw_frontend_ssl_certificate:
164 if isinstance(spec.rgw_frontend_ssl_certificate, list):
165 cert_data = '\n'.join(spec.rgw_frontend_ssl_certificate)
166 elif isinstance(spec.rgw_frontend_ssl_certificate, str):
167 cert_data = spec.rgw_frontend_ssl_certificate
168 else:
169 raise OrchestratorError(
170 'Invalid rgw_frontend_ssl_certificate: %s'
171 % spec.rgw_frontend_ssl_certificate)
172 ret, out, err = self.mgr.check_mon_command({
173 'prefix': 'config-key set',
174 'key': f'rgw/cert/{spec.rgw_realm}/{spec.rgw_zone}.crt',
175 'val': cert_data,
176 })
177
178 if spec.rgw_frontend_ssl_key:
179 if isinstance(spec.rgw_frontend_ssl_key, list):
180 key_data = '\n'.join(spec.rgw_frontend_ssl_key)
181 elif isinstance(spec.rgw_frontend_ssl_certificate, str):
182 key_data = spec.rgw_frontend_ssl_key
183 else:
184 raise OrchestratorError(
185 'Invalid rgw_frontend_ssl_key: %s'
186 % spec.rgw_frontend_ssl_key)
187 ret, out, err = self.mgr.check_mon_command({
188 'prefix': 'config-key set',
189 'key': f'rgw/cert/{spec.rgw_realm}/{spec.rgw_zone}.key',
190 'val': key_data,
191 })
192
193 logger.info('Saving service %s spec with placement %s' % (
194 spec.service_name(), spec.placement.pretty_str()))
195 self.mgr.spec_store.save(spec)
196
197 def create(self, rgw_id, host) -> str:
198 ret, keyring, err = self.mgr.check_mon_command({
199 'prefix': 'auth get-or-create',
200 'entity': f"{utils.name_to_config_section('rgw')}.{rgw_id}",
201 'caps': ['mon', 'allow *',
202 'mgr', 'allow rw',
203 'osd', 'allow rwx'],
204 })
205 return self.mgr._create_daemon('rgw', rgw_id, host, keyring=keyring)
206
207
208 class RbdMirrorService(CephadmService):
209 def create(self, daemon_id, host) -> str:
210 ret, keyring, err = self.mgr.check_mon_command({
211 'prefix': 'auth get-or-create',
212 'entity': 'client.rbd-mirror.' + daemon_id,
213 'caps': ['mon', 'profile rbd-mirror',
214 'osd', 'profile rbd'],
215 })
216 return self.mgr._create_daemon('rbd-mirror', daemon_id, host,
217 keyring=keyring)
218
219
220 class CrashService(CephadmService):
221 def create(self, daemon_id, host) -> str:
222 ret, keyring, err = self.mgr.check_mon_command({
223 'prefix': 'auth get-or-create',
224 'entity': 'client.crash.' + host,
225 'caps': ['mon', 'profile crash',
226 'mgr', 'profile crash'],
227 })
228 return self.mgr._create_daemon('crash', daemon_id, host, keyring=keyring)