]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/cephadm/services/nfs.py
Import ceph 15.2.8
[ceph.git] / ceph / src / pybind / mgr / cephadm / services / nfs.py
1 import logging
2 from typing import TYPE_CHECKING, Dict, Tuple, Any, List
3
4 from ceph.deployment.service_spec import NFSServiceSpec
5 import rados
6
7 from orchestrator import OrchestratorError, DaemonDescription
8
9 from cephadm import utils
10 from cephadm.services.cephadmservice import AuthEntity, CephadmDaemonSpec, CephService
11
12 if TYPE_CHECKING:
13 from cephadm.module import CephadmOrchestrator
14
15 logger = logging.getLogger(__name__)
16
17
18 class NFSService(CephService):
19 TYPE = 'nfs'
20
21 def config(self, spec: NFSServiceSpec) -> None:
22 assert self.TYPE == spec.service_type
23 self.mgr._check_pool_exists(spec.pool, spec.service_name())
24
25 logger.info('Saving service %s spec with placement %s' % (
26 spec.service_name(), spec.placement.pretty_str()))
27 self.mgr.spec_store.save(spec)
28
29 def prepare_create(self, daemon_spec: CephadmDaemonSpec[NFSServiceSpec]) -> CephadmDaemonSpec:
30 assert self.TYPE == daemon_spec.daemon_type
31 assert daemon_spec.spec
32
33 daemon_id = daemon_spec.daemon_id
34 host = daemon_spec.host
35 spec = daemon_spec.spec
36
37 logger.info('Create daemon %s on host %s with spec %s' % (
38 daemon_id, host, spec))
39 return daemon_spec
40
41 def generate_config(self, daemon_spec: CephadmDaemonSpec[NFSServiceSpec]) -> Tuple[Dict[str, Any], List[str]]:
42 assert self.TYPE == daemon_spec.daemon_type
43 assert daemon_spec.spec
44
45 daemon_type = daemon_spec.daemon_type
46 daemon_id = daemon_spec.daemon_id
47 host = daemon_spec.host
48 spec = daemon_spec.spec
49
50 deps: List[str] = []
51
52 # create the RADOS recovery pool keyring
53 rados_user = f'{daemon_type}.{daemon_id}'
54 rados_keyring = self.create_keyring(daemon_spec)
55
56 # create the rados config object
57 self.create_rados_config_obj(spec)
58
59 # create the RGW keyring
60 rgw_user = f'{rados_user}-rgw'
61 rgw_keyring = self.create_rgw_keyring(daemon_spec)
62
63 # generate the ganesha config
64 def get_ganesha_conf() -> str:
65 context = dict(user=rados_user,
66 nodeid=daemon_spec.name(),
67 pool=spec.pool,
68 namespace=spec.namespace if spec.namespace else '',
69 rgw_user=rgw_user,
70 url=spec.rados_config_location())
71 return self.mgr.template.render('services/nfs/ganesha.conf.j2', context)
72
73 # generate the cephadm config json
74 def get_cephadm_config() -> Dict[str, Any]:
75 config: Dict[str, Any] = {}
76 config['pool'] = spec.pool
77 if spec.namespace:
78 config['namespace'] = spec.namespace
79 config['userid'] = rados_user
80 config['extra_args'] = ['-N', 'NIV_EVENT']
81 config['files'] = {
82 'ganesha.conf': get_ganesha_conf(),
83 }
84 config.update(
85 self.get_config_and_keyring(
86 daemon_type, daemon_id,
87 keyring=rados_keyring,
88 host=host
89 )
90 )
91 config['rgw'] = {
92 'cluster': 'ceph',
93 'user': rgw_user,
94 'keyring': rgw_keyring,
95 }
96 logger.debug('Generated cephadm config-json: %s' % config)
97 return config
98
99 return get_cephadm_config(), deps
100
101 def create_rados_config_obj(self,
102 spec: NFSServiceSpec,
103 clobber: bool = False) -> None:
104 with self.mgr.rados.open_ioctx(spec.pool) as ioctx:
105 if spec.namespace:
106 ioctx.set_namespace(spec.namespace)
107
108 obj = spec.rados_config_name()
109 exists = True
110 try:
111 ioctx.stat(obj)
112 except rados.ObjectNotFound as e:
113 exists = False
114
115 if exists and not clobber:
116 # Assume an existing config
117 logger.info('Rados config object exists: %s' % obj)
118 else:
119 # Create an empty config object
120 logger.info('Creating rados config object: %s' % obj)
121 ioctx.write_full(obj, ''.encode('utf-8'))
122
123 def create_keyring(self, daemon_spec: CephadmDaemonSpec[NFSServiceSpec]) -> str:
124 assert daemon_spec.spec
125 daemon_id = daemon_spec.daemon_id
126 spec = daemon_spec.spec
127 entity: AuthEntity = self.get_auth_entity(daemon_id)
128
129 osd_caps = 'allow rw pool=%s' % (spec.pool)
130 if spec.namespace:
131 osd_caps = '%s namespace=%s' % (osd_caps, spec.namespace)
132
133 logger.info('Create keyring: %s' % entity)
134 ret, keyring, err = self.mgr.check_mon_command({
135 'prefix': 'auth get-or-create',
136 'entity': entity,
137 'caps': ['mon', 'allow r',
138 'osd', osd_caps],
139 })
140
141 return keyring
142
143 def create_rgw_keyring(self, daemon_spec: CephadmDaemonSpec[NFSServiceSpec]) -> str:
144 daemon_id = daemon_spec.daemon_id
145 entity: AuthEntity = self.get_auth_entity(f'{daemon_id}-rgw')
146
147 logger.info('Create keyring: %s' % entity)
148 ret, keyring, err = self.mgr.check_mon_command({
149 'prefix': 'auth get-or-create',
150 'entity': entity,
151 'caps': ['mon', 'allow r',
152 'osd', 'allow rwx tag rgw *=*'],
153 })
154
155 return keyring
156
157 def remove_rgw_keyring(self, daemon: DaemonDescription) -> None:
158 daemon_id: str = daemon.daemon_id
159 entity: AuthEntity = self.get_auth_entity(f'{daemon_id}-rgw')
160
161 logger.info(f'Remove keyring: {entity}')
162 ret, out, err = self.mgr.check_mon_command({
163 'prefix': 'auth rm',
164 'entity': entity,
165 })
166
167 def post_remove(self, daemon: DaemonDescription) -> None:
168 super().post_remove(daemon)
169 self.remove_rgw_keyring(daemon)