import logging
+from typing import TYPE_CHECKING, Dict, Optional, Tuple, Any, List, Set, cast
+from ceph.deployment.service_spec import NFSServiceSpec
import rados
-from typing import Dict, Optional, Tuple, Any, List, cast
-from ceph.deployment.service_spec import NFSServiceSpec
+from orchestrator import OrchestratorError, DaemonDescription
-import orchestrator
-from orchestrator import OrchestratorError
+from cephadm import utils
+from cephadm.services.cephadmservice import CephadmService, CephadmDaemonSpec
-import cephadm
-from .. import utils
+if TYPE_CHECKING:
+ from cephadm.module import CephadmOrchestrator
-from .cephadmservice import CephadmService
logger = logging.getLogger(__name__)
class NFSService(CephadmService):
- def _generate_nfs_config(self, daemon_type, daemon_id, host):
- # type: (str, str, str) -> Tuple[Dict[str, Any], List[str]]
- deps = [] # type: List[str]
+ TYPE = 'nfs'
+
+ def generate_config(self, daemon_spec: CephadmDaemonSpec) -> Tuple[Dict[str, Any], List[str]]:
+ assert self.TYPE == daemon_spec.daemon_type
+
+ daemon_type = daemon_spec.daemon_type
+ daemon_id = daemon_spec.daemon_id
+ host = daemon_spec.host
+
+ deps: List[str] = []
# find the matching NFSServiceSpec
# TODO: find the spec and pass via _create_daemon instead ??
- dd = orchestrator.DaemonDescription()
+ dd = DaemonDescription()
dd.daemon_type = daemon_type
dd.daemon_id = daemon_id
dd.hostname = host
# generate the cephadm config
cephadm_config = nfs.get_cephadm_config()
cephadm_config.update(
- self.mgr._get_config_and_keyring(
- daemon_type, daemon_id,
- keyring=keyring))
+ self.mgr._get_config_and_keyring(
+ daemon_type, daemon_id,
+ keyring=keyring,
+ host=host
+ )
+ )
return cephadm_config, deps
- def config(self, spec):
+ def config(self, spec: NFSServiceSpec) -> None:
+ assert self.TYPE == spec.service_type
self.mgr._check_pool_exists(spec.pool, spec.service_name())
+
logger.info('Saving service %s spec with placement %s' % (
spec.service_name(), spec.placement.pretty_str()))
self.mgr.spec_store.save(spec)
- def create(self, daemon_id, host, spec):
+ def create(self, daemon_spec: CephadmDaemonSpec[NFSServiceSpec]) -> str:
+ assert self.TYPE == daemon_spec.daemon_type
+ assert daemon_spec.spec
+
+ daemon_id = daemon_spec.daemon_id
+ host = daemon_spec.host
+ spec = daemon_spec.spec
+
logger.info('Create daemon %s on host %s with spec %s' % (
daemon_id, host, spec))
- return self.mgr._create_daemon('nfs', daemon_id, host)
+ return self.mgr._create_daemon(daemon_spec)
+
+ def config_dashboard(self, daemon_descrs: List[DaemonDescription]):
+
+ def get_set_cmd_dicts(out: str) -> List[dict]:
+ locations: Set[str] = set()
+ for dd in daemon_descrs:
+ spec = cast(NFSServiceSpec,
+ self.mgr.spec_store.specs.get(dd.service_name(), None))
+ if not spec or not spec.service_id:
+ logger.warning('No ServiceSpec or service_id found for %s', dd)
+ continue
+ location = '{}:{}'.format(spec.service_id, spec.pool)
+ if spec.namespace:
+ location = '{}/{}'.format(location, spec.namespace)
+ locations.add(location)
+ new_value = ','.join(locations)
+ if new_value and new_value != out:
+ return [{'prefix': 'dashboard set-ganesha-clusters-rados-pool-namespace',
+ 'value': new_value}]
+ return []
+
+ self._check_and_set_dashboard(
+ service_name='Ganesha',
+ get_cmd='dashboard get-ganesha-clusters-rados-pool-namespace',
+ get_set_cmd_dicts=get_set_cmd_dicts
+ )
class NFSGanesha(object):
def __init__(self,
- mgr,
- daemon_id,
- spec):
- # type: (cephadm.CephadmOrchestrator, str, NFSServiceSpec) -> None
+ mgr: "CephadmOrchestrator",
+ daemon_id: str,
+ spec: NFSServiceSpec) -> None:
assert spec.service_id and daemon_id.startswith(spec.service_id)
+ mgr._check_pool_exists(spec.pool, spec.service_name())
+
self.mgr = mgr
self.daemon_id = daemon_id
self.spec = spec
- def get_daemon_name(self):
- # type: () -> str
+ def get_daemon_name(self) -> str:
return '%s.%s' % (self.spec.service_type, self.daemon_id)
- def get_rados_user(self):
- # type: () -> str
+ def get_rados_user(self) -> str:
return '%s.%s' % (self.spec.service_type, self.daemon_id)
- def get_keyring_entity(self):
- # type: () -> str
+ def get_keyring_entity(self) -> str:
return utils.name_to_config_section(self.get_rados_user())
- def get_or_create_keyring(self, entity=None):
- # type: (Optional[str]) -> str
+ def get_or_create_keyring(self, entity: Optional[str] = None) -> str:
if not entity:
entity = self.get_keyring_entity()
if ret != 0:
raise OrchestratorError(
- 'Unable to create keyring %s: %s %s' \
- % (entity, ret, err))
+ 'Unable to create keyring %s: %s %s'
+ % (entity, ret, err))
return keyring
- def update_keyring_caps(self, entity=None):
- # type: (Optional[str]) -> None
+ def update_keyring_caps(self, entity: Optional[str] = None) -> None:
if not entity:
entity = self.get_keyring_entity()
- osd_caps='allow rw pool=%s' % (self.spec.pool)
+ osd_caps = 'allow rw pool=%s' % (self.spec.pool)
if self.spec.namespace:
- osd_caps='%s namespace=%s' % (osd_caps, self.spec.namespace)
+ osd_caps = '%s namespace=%s' % (osd_caps, self.spec.namespace)
logger.info('Updating keyring caps: %s' % entity)
ret, out, err = self.mgr.mon_command({
if ret != 0:
raise OrchestratorError(
- 'Unable to update keyring caps %s: %s %s' \
- % (entity, ret, err))
-
- def create_rados_config_obj(self, clobber=False):
- # type: (Optional[bool]) -> None
- obj = self.spec.rados_config_name()
+ 'Unable to update keyring caps %s: %s %s'
+ % (entity, ret, err))
+ def create_rados_config_obj(self, clobber: Optional[bool] = False) -> None:
with self.mgr.rados.open_ioctx(self.spec.pool) as ioctx:
if self.spec.namespace:
ioctx.set_namespace(self.spec.namespace)
+ obj = self.spec.rados_config_name()
exists = True
try:
ioctx.stat(obj)
logger.info('Creating rados config object: %s' % obj)
ioctx.write_full(obj, ''.encode('utf-8'))
- def get_ganesha_conf(self):
- # type: () -> str
+ def get_ganesha_conf(self) -> str:
context = dict(user=self.get_rados_user(),
nodeid=self.get_daemon_name(),
pool=self.spec.pool,
url=self.spec.rados_config_location())
return self.mgr.template.render('services/nfs/ganesha.conf.j2', context)
- def get_cephadm_config(self):
- # type: () -> Dict
- config = {'pool' : self.spec.pool} # type: Dict
+ def get_cephadm_config(self) -> Dict[str, Any]:
+ config: Dict[str, Any] = {'pool': self.spec.pool}
if self.spec.namespace:
config['namespace'] = self.spec.namespace
config['userid'] = self.get_rados_user()
config['extra_args'] = ['-N', 'NIV_EVENT']
config['files'] = {
- 'ganesha.conf' : self.get_ganesha_conf(),
+ 'ganesha.conf': self.get_ganesha_conf(),
}
logger.debug('Generated cephadm config-json: %s' % config)
return config