]> git.proxmox.com Git - ceph.git/blame - ceph/src/pybind/mgr/cephadm/services/iscsi.py
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / pybind / mgr / cephadm / services / iscsi.py
CommitLineData
f67539c2 1import errno
e306af50
TL
2import json
3import logging
f67539c2
TL
4from typing import List, cast, Optional
5from ipaddress import ip_address, IPv6Address
e306af50 6
f67539c2 7from mgr_module import HandleCommandResult
e306af50
TL
8from ceph.deployment.service_spec import IscsiServiceSpec
9
f67539c2
TL
10from orchestrator import DaemonDescription, DaemonDescriptionStatus
11from .cephadmservice import CephadmDaemonDeploySpec, CephService
e306af50
TL
12from .. import utils
13
14logger = logging.getLogger(__name__)
15
16
f91f0fd5 17class IscsiService(CephService):
f6b5b4d7
TL
18 TYPE = 'iscsi'
19
f67539c2 20 def config(self, spec: IscsiServiceSpec, daemon_id: str) -> None: # type: ignore
f6b5b4d7 21 assert self.TYPE == spec.service_type
adb31ebb 22 assert spec.pool
e306af50
TL
23 self.mgr._check_pool_exists(spec.pool, spec.service_name())
24
f67539c2 25 def prepare_create(self, daemon_spec: CephadmDaemonDeploySpec) -> CephadmDaemonDeploySpec:
f6b5b4d7 26 assert self.TYPE == daemon_spec.daemon_type
f6b5b4d7 27
f67539c2 28 spec = cast(IscsiServiceSpec, self.mgr.spec_store[daemon_spec.service_name].spec)
f6b5b4d7
TL
29 igw_id = daemon_spec.daemon_id
30
f67539c2
TL
31 keyring = self.get_keyring_with_caps(self.get_auth_entity(igw_id),
32 ['mon', 'profile rbd, '
33 'allow command "osd blocklist", '
34 'allow command "config-key get" with "key" prefix "iscsi/"',
35 'mgr', 'allow command "service status"',
36 'osd', 'allow rwx'])
e306af50
TL
37
38 if spec.ssl_cert:
39 if isinstance(spec.ssl_cert, list):
40 cert_data = '\n'.join(spec.ssl_cert)
41 else:
42 cert_data = spec.ssl_cert
f91f0fd5 43 ret, out, err = self.mgr.check_mon_command({
e306af50
TL
44 'prefix': 'config-key set',
45 'key': f'iscsi/{utils.name_to_config_section("iscsi")}.{igw_id}/iscsi-gateway.crt',
46 'val': cert_data,
47 })
48
49 if spec.ssl_key:
50 if isinstance(spec.ssl_key, list):
51 key_data = '\n'.join(spec.ssl_key)
52 else:
53 key_data = spec.ssl_key
f91f0fd5 54 ret, out, err = self.mgr.check_mon_command({
e306af50
TL
55 'prefix': 'config-key set',
56 'key': f'iscsi/{utils.name_to_config_section("iscsi")}.{igw_id}/iscsi-gateway.key',
57 'val': key_data,
58 })
59
60 context = {
61 'client_name': '{}.{}'.format(utils.name_to_config_section('iscsi'), igw_id),
62 'spec': spec
63 }
64 igw_conf = self.mgr.template.render('services/iscsi/iscsi-gateway.cfg.j2', context)
f6b5b4d7
TL
65
66 daemon_spec.keyring = keyring
f91f0fd5 67 daemon_spec.extra_files = {'iscsi-gateway.cfg': igw_conf}
f6b5b4d7 68
f67539c2
TL
69 daemon_spec.final_config, daemon_spec.deps = self.generate_config(daemon_spec)
70
f91f0fd5 71 return daemon_spec
f6b5b4d7 72
f91f0fd5 73 def config_dashboard(self, daemon_descrs: List[DaemonDescription]) -> None:
f6b5b4d7
TL
74 def get_set_cmd_dicts(out: str) -> List[dict]:
75 gateways = json.loads(out)['gateways']
76 cmd_dicts = []
f67539c2 77 # TODO: fail, if we don't have a spec
adb31ebb 78 spec = cast(IscsiServiceSpec,
f67539c2 79 self.mgr.spec_store.all_specs.get(daemon_descrs[0].service_name(), None))
adb31ebb
TL
80 if spec.api_secure and spec.ssl_cert and spec.ssl_key:
81 cmd_dicts.append({
82 'prefix': 'dashboard set-iscsi-api-ssl-verification',
83 'value': "false"
84 })
85 else:
86 cmd_dicts.append({
87 'prefix': 'dashboard set-iscsi-api-ssl-verification',
88 'value': "true"
89 })
f6b5b4d7 90 for dd in daemon_descrs:
f67539c2
TL
91 assert dd.hostname is not None
92 # todo: this can fail:
f6b5b4d7 93 spec = cast(IscsiServiceSpec,
f67539c2 94 self.mgr.spec_store.all_specs.get(dd.service_name(), None))
f6b5b4d7
TL
95 if not spec:
96 logger.warning('No ServiceSpec found for %s', dd)
97 continue
adb31ebb 98 ip = utils.resolve_ip(dd.hostname)
f67539c2
TL
99 # IPv6 URL encoding requires square brackets enclosing the ip
100 if type(ip_address(ip)) is IPv6Address:
101 ip = f'[{ip}]'
adb31ebb
TL
102 protocol = "http"
103 if spec.api_secure and spec.ssl_cert and spec.ssl_key:
104 protocol = "https"
105 service_url = '{}://{}:{}@{}:{}'.format(
106 protocol, spec.api_user or 'admin', spec.api_password or 'admin', ip, spec.api_port or '5000')
107 gw = gateways.get(dd.hostname)
f6b5b4d7 108 if not gw or gw['service_url'] != service_url:
adb31ebb
TL
109 safe_service_url = '{}://{}:{}@{}:{}'.format(
110 protocol, '<api-user>', '<api-password>', ip, spec.api_port or '5000')
111 logger.info('Adding iSCSI gateway %s to Dashboard', safe_service_url)
f6b5b4d7 112 cmd_dicts.append({
e306af50 113 'prefix': 'dashboard iscsi-gateway-add',
cd265ab1 114 'inbuf': service_url,
adb31ebb 115 'name': dd.hostname
e306af50 116 })
f6b5b4d7
TL
117 return cmd_dicts
118
119 self._check_and_set_dashboard(
120 service_name='iSCSI',
121 get_cmd='dashboard iscsi-gateway-list',
122 get_set_cmd_dicts=get_set_cmd_dicts
123 )
f67539c2
TL
124
125 def ok_to_stop(self,
126 daemon_ids: List[str],
127 force: bool = False,
128 known: Optional[List[str]] = None) -> HandleCommandResult:
129 # if only 1 iscsi, alert user (this is not passable with --force)
130 warn, warn_message = self._enough_daemons_to_stop(self.TYPE, daemon_ids, 'Iscsi', 1, True)
131 if warn:
132 return HandleCommandResult(-errno.EBUSY, '', warn_message)
133
134 # if reached here, there is > 1 nfs daemon. make sure none are down
135 warn_message = (
136 'ALERT: 1 iscsi daemon is already down. Please bring it back up before stopping this one')
137 iscsi_daemons = self.mgr.cache.get_daemons_by_type(self.TYPE)
138 for i in iscsi_daemons:
139 if i.status != DaemonDescriptionStatus.running:
140 return HandleCommandResult(-errno.EBUSY, '', warn_message)
141
142 names = [f'{self.TYPE}.{d_id}' for d_id in daemon_ids]
143 warn_message = f'It is presumed safe to stop {names}'
144 return HandleCommandResult(0, warn_message, '')