unlink_file,
write_new,
write_tmp,
+ update_meta_file,
)
from cephadmlib.net_utils import (
build_addrv_params,
detail: bool = True,
legacy_dir: Optional[str] = None,
daemon_name: Optional[str] = None,
+ type_of_daemon: Optional[str] = None,
) -> List[Dict[str, str]]:
host_version: Optional[str] = None
ls = []
if os.path.exists(data_dir):
for i in os.listdir(data_dir):
if i in ['mon', 'osd', 'mds', 'mgr', 'rgw']:
+ if type_of_daemon and type_of_daemon != i:
+ continue
daemon_type = i
for j in os.listdir(os.path.join(data_dir, i)):
if '-' not in j:
if daemon_name and name != daemon_name:
continue
(daemon_type, daemon_id) = j.split('.', 1)
+ if type_of_daemon and type_of_daemon != daemon_type:
+ continue
unit_name = get_unit_name(fsid,
daemon_type,
daemon_id)
# print default images
cp_obj.write(sys.stdout)
+
+def update_service_for_daemon(ctx: CephadmContext,
+ available_daemons: list,
+ update_daemons: list) -> None:
+ """ Update the unit.meta file of daemon with required service name for valid daemons"""
+
+ data = {'service_name': ctx.service_name}
+ # check if all the daemon names are valid
+ if not set(update_daemons).issubset(set(available_daemons)):
+ raise Error(f'Error EINVAL: one or more daemons of {update_daemons} does not exist on this host')
+ for name in update_daemons:
+ path = os.path.join(ctx.data_dir, ctx.fsid, name, 'unit.meta')
+ update_meta_file(path, data)
+ print(f'Successfully updated daemon {name} with service {ctx.service_name}')
+
+
+@infer_fsid
+def command_update_osd_service(ctx: CephadmContext) -> int:
+ """update service for provided daemon"""
+ update_daemons = [f'osd.{osd_id}' for osd_id in ctx.osd_ids.split(',')]
+ daemons = list_daemons(ctx, detail=False, type_of_daemon='osd')
+ if not daemons:
+ raise Error(f'Daemon {ctx.osd_ids} does not exists on this host')
+ available_daemons = [d['name'] for d in daemons]
+ update_service_for_daemon(ctx, available_daemons, update_daemons)
+ return 0
+
+
##################################
parser_list_images = subparsers.add_parser(
'list-images', help='list all the default images')
parser_list_images.set_defaults(func=command_list_images)
+
+ parser_update_service = subparsers.add_parser(
+ 'update-osd-service', help='update service for provided daemon')
+ parser_update_service.set_defaults(func=command_update_osd_service)
+ parser_update_service.add_argument('--fsid', help='cluster FSID')
+ parser_update_service.add_argument('--osd-ids', required=True, help='Comma-separated OSD IDs')
+ parser_update_service.add_argument('--service-name', required=True, help='OSD service name')
+
return parser
import logging
import os
import tempfile
+import json
from contextlib import contextmanager
from pathlib import Path
except Exception:
if not ignore_errors:
raise
+
+
+def update_meta_file(file_path: str, update_key_val: dict) -> None:
+ """Update key in the file with provided value"""
+ try:
+ with open(file_path, 'r') as fh:
+ data = json.load(fh)
+ file_stat = os.stat(file_path)
+ except FileNotFoundError:
+ raise
+ except Exception:
+ logger.exception(f'Failed to update {file_path}')
+ raise
+ data.update(
+ {key: value for key, value in update_key_val.items() if key in data}
+ )
+
+ with write_new(
+ file_path,
+ owner=(file_stat.st_uid, file_stat.st_gid),
+ perms=(file_stat.st_mode & 0o777),
+ ) as fh:
+ fh.write(json.dumps(data, indent=4) + '\n')
@handle_orch_error
def service_action(self, action: str, service_name: str) -> List[str]:
- if service_name not in self.spec_store.all_specs.keys():
+ if service_name not in self.spec_store.all_specs.keys() and service_name != 'osd':
raise OrchestratorError(f'Invalid service name "{service_name}".'
+ ' View currently running services using "ceph orch ls"')
dds: List[DaemonDescription] = self.cache.get_daemons_by_service(service_name)
"""
return self.to_remove_osds.all_osds()
+ @handle_orch_error
+ def set_osd_spec(self, service_name: str, osd_ids: List[str]) -> str:
+ """
+ Update unit.meta file for osd with service name
+ """
+ if service_name not in self.spec_store:
+ raise OrchestratorError(f"Cannot find service '{service_name}' in the inventory. "
+ "Please try again after applying an OSD service that matches "
+ "the service name to which you want to attach OSDs.")
+
+ daemons: List[orchestrator.DaemonDescription] = self.cache.get_daemons_by_type('osd')
+ update_osd = defaultdict(list)
+ for daemon in daemons:
+ if daemon.daemon_id in osd_ids and daemon.hostname:
+ update_osd[daemon.hostname].append(daemon.daemon_id)
+
+ if not update_osd:
+ raise OrchestratorError(f"Unable to find OSDs: {osd_ids}")
+
+ failed_osds = []
+ success_osds = []
+ for host in update_osd:
+ osds = ",".join(update_osd[host])
+ # run cephadm command with all host osds on specific host,
+ # if it fails, continue with other hosts
+ try:
+ with self.async_timeout_handler(host):
+ outs, errs, _code = self.wait_async(
+ CephadmServe(self)._run_cephadm(host,
+ cephadmNoImage,
+ 'update-osd-service',
+ ['--service-name', service_name, '--osd-ids', osds]))
+ if _code:
+ self.log.error(f"Failed to update service for {osds} osd. Cephadm error: {errs}")
+ failed_osds.extend(update_osd[host])
+ else:
+ success_osds.extend(update_osd[host])
+ except Exception:
+ self.log.exception(f"Failed to set service name for {osds}")
+ failed_osds.extend(update_osd[host])
+ self.cache.invalidate_host_daemons(host)
+ self._kick_serve_loop()
+ return f"Updated service for osd {','.join(success_osds)}" + (f" and failed for {','.join(failed_osds)}" if failed_osds else "")
+
@handle_orch_error
@host_exists()
def drain_host(self, hostname: str, force: bool = False, keep_conf_keyring: bool = False, zap_osd_devices: bool = False) -> str:
"""
raise NotImplementedError()
+ def set_osd_spec(self, service_name: str, osd_ids: List[str]) -> OrchResult:
+ """ set service of osd """
+ raise NotImplementedError()
+
def blink_device_light(self, ident_fault: str, on: bool, locations: List['DeviceLightLoc']) -> OrchResult[List[str]]:
"""
Instructs the orchestrator to enable or disable either the ident or the fault LED.
return HandleCommandResult(stdout=out)
+ @_cli_write_command('orch osd set-spec-affinity')
+ def _osd_set_spec(self, service_name: str, osd_id: List[str]) -> HandleCommandResult:
+ """Set service spec affinity for osd"""
+ completion = self.set_osd_spec(service_name, osd_id)
+ res = raise_if_exception(completion)
+
+ return HandleCommandResult(stdout=res)
+
@_cli_write_command('orch daemon add')
def daemon_add_misc(self,
daemon_type: Optional[ServiceType] = None,