]>
git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/cephadm/services/nfs.py
2 from typing
import TYPE_CHECKING
, Dict
, Optional
, Tuple
, Any
, List
, Set
, cast
4 from ceph
.deployment
.service_spec
import NFSServiceSpec
7 from orchestrator
import OrchestratorError
, DaemonDescription
9 from cephadm
import utils
10 from cephadm
.services
.cephadmservice
import CephadmService
, CephadmDaemonSpec
13 from cephadm
.module
import CephadmOrchestrator
15 logger
= logging
.getLogger(__name__
)
18 class NFSService(CephadmService
):
21 def generate_config(self
, daemon_spec
: CephadmDaemonSpec
) -> Tuple
[Dict
[str, Any
], List
[str]]:
22 assert self
.TYPE
== daemon_spec
.daemon_type
24 daemon_type
= daemon_spec
.daemon_type
25 daemon_id
= daemon_spec
.daemon_id
26 host
= daemon_spec
.host
30 # find the matching NFSServiceSpec
31 # TODO: find the spec and pass via _create_daemon instead ??
32 dd
= DaemonDescription()
33 dd
.daemon_type
= daemon_type
34 dd
.daemon_id
= daemon_id
37 service_name
= dd
.service_name()
38 specs
= self
.mgr
.spec_store
.find(service_name
)
41 raise OrchestratorError('Cannot find service spec %s' % (service_name
))
43 raise OrchestratorError('Found multiple service specs for %s' % (service_name
))
45 # cast to keep mypy happy
46 spec
= cast(NFSServiceSpec
, specs
[0])
48 nfs
= NFSGanesha(self
.mgr
, daemon_id
, spec
)
51 entity
= nfs
.get_keyring_entity()
52 keyring
= nfs
.get_or_create_keyring(entity
=entity
)
54 # update the caps after get-or-create, the keyring might already exist!
55 nfs
.update_keyring_caps(entity
=entity
)
57 # create the rados config object
58 nfs
.create_rados_config_obj()
60 # generate the cephadm config
61 cephadm_config
= nfs
.get_cephadm_config()
62 cephadm_config
.update(
63 self
.mgr
._get
_config
_and
_keyring
(
64 daemon_type
, daemon_id
,
70 return cephadm_config
, deps
72 def config(self
, spec
: NFSServiceSpec
) -> None:
73 assert self
.TYPE
== spec
.service_type
74 self
.mgr
._check
_pool
_exists
(spec
.pool
, spec
.service_name())
76 logger
.info('Saving service %s spec with placement %s' % (
77 spec
.service_name(), spec
.placement
.pretty_str()))
78 self
.mgr
.spec_store
.save(spec
)
80 def create(self
, daemon_spec
: CephadmDaemonSpec
[NFSServiceSpec
]) -> str:
81 assert self
.TYPE
== daemon_spec
.daemon_type
82 assert daemon_spec
.spec
84 daemon_id
= daemon_spec
.daemon_id
85 host
= daemon_spec
.host
86 spec
= daemon_spec
.spec
88 logger
.info('Create daemon %s on host %s with spec %s' % (
89 daemon_id
, host
, spec
))
90 return self
.mgr
._create
_daemon
(daemon_spec
)
92 def config_dashboard(self
, daemon_descrs
: List
[DaemonDescription
]):
94 def get_set_cmd_dicts(out
: str) -> List
[dict]:
95 locations
: Set
[str] = set()
96 for dd
in daemon_descrs
:
97 spec
= cast(NFSServiceSpec
,
98 self
.mgr
.spec_store
.specs
.get(dd
.service_name(), None))
99 if not spec
or not spec
.service_id
:
100 logger
.warning('No ServiceSpec or service_id found for %s', dd
)
102 location
= '{}:{}'.format(spec
.service_id
, spec
.pool
)
104 location
= '{}/{}'.format(location
, spec
.namespace
)
105 locations
.add(location
)
106 new_value
= ','.join(locations
)
107 if new_value
and new_value
!= out
:
108 return [{'prefix': 'dashboard set-ganesha-clusters-rados-pool-namespace',
112 self
._check
_and
_set
_dashboard
(
113 service_name
='Ganesha',
114 get_cmd
='dashboard get-ganesha-clusters-rados-pool-namespace',
115 get_set_cmd_dicts
=get_set_cmd_dicts
119 class NFSGanesha(object):
121 mgr
: "CephadmOrchestrator",
123 spec
: NFSServiceSpec
) -> None:
124 assert spec
.service_id
and daemon_id
.startswith(spec
.service_id
)
125 mgr
._check
_pool
_exists
(spec
.pool
, spec
.service_name())
128 self
.daemon_id
= daemon_id
131 def get_daemon_name(self
) -> str:
132 return '%s.%s' % (self
.spec
.service_type
, self
.daemon_id
)
134 def get_rados_user(self
) -> str:
135 return '%s.%s' % (self
.spec
.service_type
, self
.daemon_id
)
137 def get_keyring_entity(self
) -> str:
138 return utils
.name_to_config_section(self
.get_rados_user())
140 def get_or_create_keyring(self
, entity
: Optional
[str] = None) -> str:
142 entity
= self
.get_keyring_entity()
144 logger
.info('Create keyring: %s' % entity
)
145 ret
, keyring
, err
= self
.mgr
.mon_command({
146 'prefix': 'auth get-or-create',
151 raise OrchestratorError(
152 'Unable to create keyring %s: %s %s'
153 % (entity
, ret
, err
))
156 def update_keyring_caps(self
, entity
: Optional
[str] = None) -> None:
158 entity
= self
.get_keyring_entity()
160 osd_caps
= 'allow rw pool=%s' % (self
.spec
.pool
)
161 if self
.spec
.namespace
:
162 osd_caps
= '%s namespace=%s' % (osd_caps
, self
.spec
.namespace
)
164 logger
.info('Updating keyring caps: %s' % entity
)
165 ret
, out
, err
= self
.mgr
.mon_command({
166 'prefix': 'auth caps',
168 'caps': ['mon', 'allow r',
173 raise OrchestratorError(
174 'Unable to update keyring caps %s: %s %s'
175 % (entity
, ret
, err
))
177 def create_rados_config_obj(self
, clobber
: Optional
[bool] = False) -> None:
178 with self
.mgr
.rados
.open_ioctx(self
.spec
.pool
) as ioctx
:
179 if self
.spec
.namespace
:
180 ioctx
.set_namespace(self
.spec
.namespace
)
182 obj
= self
.spec
.rados_config_name()
186 except rados
.ObjectNotFound
as e
:
189 if exists
and not clobber
:
190 # Assume an existing config
191 logger
.info('Rados config object exists: %s' % obj
)
193 # Create an empty config object
194 logger
.info('Creating rados config object: %s' % obj
)
195 ioctx
.write_full(obj
, ''.encode('utf-8'))
197 def get_ganesha_conf(self
) -> str:
198 context
= dict(user
=self
.get_rados_user(),
199 nodeid
=self
.get_daemon_name(),
201 namespace
=self
.spec
.namespace
if self
.spec
.namespace
else '',
202 url
=self
.spec
.rados_config_location())
203 return self
.mgr
.template
.render('services/nfs/ganesha.conf.j2', context
)
205 def get_cephadm_config(self
) -> Dict
[str, Any
]:
206 config
: Dict
[str, Any
] = {'pool': self
.spec
.pool
}
207 if self
.spec
.namespace
:
208 config
['namespace'] = self
.spec
.namespace
209 config
['userid'] = self
.get_rados_user()
210 config
['extra_args'] = ['-N', 'NIV_EVENT']
212 'ganesha.conf': self
.get_ganesha_conf(),
214 logger
.debug('Generated cephadm config-json: %s' % config
)