From: Kefu Chai Date: Sun, 27 Dec 2020 14:45:24 +0000 (+0800) Subject: pybind/mgr/orchestrator: use enum parameter when appropriate X-Git-Tag: v17.0.0~52^2~11 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=3e41343db9ca630031eeda54b8bf86e573b98885;p=ceph-ci.git pybind/mgr/orchestrator: use enum parameter when appropriate and move desc as docstring. Signed-off-by: Kefu Chai --- diff --git a/src/pybind/mgr/orchestrator/module.py b/src/pybind/mgr/orchestrator/module.py index c2af2f3a2ea..9f97fe9499e 100644 --- a/src/pybind/mgr/orchestrator/module.py +++ b/src/pybind/mgr/orchestrator/module.py @@ -1,3 +1,4 @@ +import enum import errno import json from typing import List, Set, Optional, Iterator, cast, Dict, Any, Union @@ -29,7 +30,45 @@ def nice_delta(now, t, suffix=''): return '-' -def to_format(what, format: str, many: bool, cls): +class Format(enum.Enum): + plain = 'plain' + json = 'json' + json_pretty = 'json-pretty' + yaml = 'yaml' + + +class ServiceType(enum.Enum): + mon = 'mon' + mgr = 'mgr' + rbd_mirror = 'rbd-mirror' + crash = 'crash' + alertmanager = 'alertmanager' + grafana = 'grafana' + node_exporter = 'node-exporter' + prometheus = 'prometheus' + mds = 'mds' + rgw = 'rgw' + nfs = 'nfs' + iscsi = 'iscsi' + cephadm_exporter = 'cephadm-exporter' + + +class ServiceAction(enum.Enum): + start = 'start' + stop = 'stop' + restart = 'restart' + redeploy = 'redeploy' + reconfig = 'reconfig' + + +class DaemonAction(enum.Enum): + start = 'start' + stop = 'stop' + restart = 'restart' + reconfig = 'reconfig' + + +def to_format(what, format: Format, many: bool, cls): def to_json_1(obj): if hasattr(obj, 'to_json'): return obj.to_json() @@ -40,11 +79,11 @@ def to_format(what, format: str, many: bool, cls): to_json = to_json_n if many else to_json_1 - if format == 'json': + if format == Format.json: return json.dumps(to_json(what), sort_keys=True) - elif format == 'json-pretty': + elif format == Format.json_pretty: return json.dumps(to_json(what), indent=2, sort_keys=True) - elif format == 'yaml': + elif format == Format.yaml: # fun with subinterpreters again. pyyaml depends on object identity. # as what originates from a different subinterpreter we have to copy things here. if cls: @@ -203,10 +242,9 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule, locs = [d['location'] for d in self.get('devices')['devices'] if d['devid'] == dev_id] return [DeviceLightLoc(**l) for l in sum(locs, [])] - @_cli_read_command( - prefix='device ls-lights', - desc='List currently active device indicator lights') + @_cli_read_command(prefix='device ls-lights') def _device_ls(self): + """List currently active device indicator lights""" return HandleCommandResult( stdout=json.dumps({ 'ident': list(self.ident), @@ -257,69 +295,64 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule, self._refresh_health() raise - @_cli_write_command( - prefix='device light', - cmd_args='name=enable,type=CephChoices,strings=on|off ' - 'name=devid,type=CephString ' - 'name=light_type,type=CephChoices,strings=ident|fault,req=false ' - 'name=force,type=CephBool,req=false', - desc='Enable or disable the device light. Default type is `ident`\n' - 'Usage: device light (on|off) [ident|fault] [--force]') - def _device_light(self, enable, devid, light_type=None, force=False): - # type: (str, str, Optional[str], bool) -> HandleCommandResult - light_type = light_type or 'ident' - on = enable == 'on' - if on: - return self.light_on(light_type, devid) + class DeviceLightEnable(enum.Enum): + on = 'on' + off = 'off' + + class DeviceLightType(enum.Enum): + ident = 'ident' + fault = 'fault' + + @_cli_write_command(prefix='device light') + def _device_light(self, + enable: DeviceLightEnable, + devid: str, + light_type: DeviceLightType = DeviceLightType.ident, + force: bool = False) -> HandleCommandResult: + """ + Enable or disable the device light. Default type is `ident` + 'Usage: device light (on|off) [ident|fault] [--force]' + """"" + if enable == self.DeviceLightEnable.on: + return self.light_on(light_type.value, devid) else: - return self.light_off(light_type, devid, force) + return self.light_off(light_type.value, devid, force) def _select_orchestrator(self): return self.get_module_option("orchestrator") - @_cli_write_command( - 'orch host add', - 'name=hostname,type=CephString,req=true ' - 'name=addr,type=CephString,req=false ' - 'name=labels,type=CephString,n=N,req=false', - 'Add a host') + @_cli_write_command('orch host add') def _add_host(self, hostname: str, addr: Optional[str] = None, labels: Optional[List[str]] = None): + """Add a host""" s = HostSpec(hostname=hostname, addr=addr, labels=labels) completion = self.add_host(s) self._orchestrator_wait([completion]) raise_if_exception(completion) return HandleCommandResult(stdout=completion.result_str()) - @_cli_write_command( - 'orch host rm', - "name=hostname,type=CephString,req=true", - 'Remove a host') - def _remove_host(self, hostname): + @_cli_write_command('orch host rm') + def _remove_host(self, hostname: str): + """Remove a host""" completion = self.remove_host(hostname) self._orchestrator_wait([completion]) raise_if_exception(completion) return HandleCommandResult(stdout=completion.result_str()) - @_cli_write_command( - 'orch host set-addr', - 'name=hostname,type=CephString ' - 'name=addr,type=CephString', - 'Update a host address') - def _update_set_addr(self, hostname, addr): + @_cli_write_command('orch host set-addr') + def _update_set_addr(self, hostname: str, addr: str): + """Update a host address""" completion = self.update_host_addr(hostname, addr) self._orchestrator_wait([completion]) raise_if_exception(completion) return HandleCommandResult(stdout=completion.result_str()) - @_cli_read_command( - 'orch host ls', - 'name=format,type=CephChoices,strings=plain|json|json-pretty|yaml,req=false', - 'List hosts') - def _get_hosts(self, format='plain'): + @_cli_read_command('orch host ls') + def _get_hosts(self, format: Format = Format.plain): + """List hosts""" completion = self.get_hosts() self._orchestrator_wait([completion]) raise_if_exception(completion) - if format != 'plain': + if format != Format.plain: output = to_format(completion.result, format, many=True, cls=HostSpec) else: table = PrettyTable( @@ -334,43 +367,36 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule, output = table.get_string() return HandleCommandResult(stdout=output) - @_cli_write_command( - 'orch host label add', - 'name=hostname,type=CephString ' - 'name=label,type=CephString', - 'Add a host label') - def _host_label_add(self, hostname, label): + @_cli_write_command('orch host label add') + def _host_label_add(self, hostname: str, label: str): + """Add a host label""" completion = self.add_host_label(hostname, label) self._orchestrator_wait([completion]) raise_if_exception(completion) return HandleCommandResult(stdout=completion.result_str()) - @_cli_write_command( - 'orch host label rm', - 'name=hostname,type=CephString ' - 'name=label,type=CephString', - 'Remove a host label') - def _host_label_rm(self, hostname, label): + @_cli_write_command('orch host label rm') + def _host_label_rm(self, hostname: str, label: str): + """Remove a host label""" completion = self.remove_host_label(hostname, label) self._orchestrator_wait([completion]) raise_if_exception(completion) return HandleCommandResult(stdout=completion.result_str()) - @_cli_write_command( - 'orch host ok-to-stop', - 'name=hostname,type=CephString', - desc='Check if the specified host can be safely stopped without reducing availability') + @_cli_write_command('orch host ok-to-stop') def _host_ok_to_stop(self, hostname: str): + """Check if the specified host can be safely stopped without reducing availability""""" completion = self.host_ok_to_stop(hostname) self._orchestrator_wait([completion]) raise_if_exception(completion) return HandleCommandResult(stdout=completion.result_str()) @_cli_write_command( - 'orch host maintenance enter', - 'name=hostname,type=CephString', - desc='Prepare a host for maintenance by shutting down and disabling all Ceph daemons (cephadm only)') + 'orch host maintenance enter') def _host_maintenance_enter(self, hostname: str): + """ + Prepare a host for maintenance by shutting down and disabling all Ceph daemons (cephadm only) + """ completion = self.enter_host_maintenance(hostname) self._orchestrator_wait([completion]) raise_if_exception(completion) @@ -378,32 +404,31 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule, return HandleCommandResult(stdout=completion.result_str()) @_cli_write_command( - 'orch host maintenance exit', - 'name=hostname,type=CephString', - desc='Return a host from maintenance, restarting all Ceph daemons (cephadm only)') + 'orch host maintenance exit') def _host_maintenance_exit(self, hostname: str): + """ + Return a host from maintenance, restarting all Ceph daemons (cephadm only) + """ completion = self.exit_host_maintenance(hostname) self._orchestrator_wait([completion]) raise_if_exception(completion) return HandleCommandResult(stdout=completion.result_str()) - @_cli_read_command( - 'orch device ls', - "name=hostname,type=CephString,n=N,req=false " - "name=format,type=CephChoices,strings=plain|json|json-pretty|yaml,req=false " - "name=refresh,type=CephBool,req=false " - "name=wide,type=CephBool,req=false", - 'List devices on a host') - def _list_devices(self, hostname=None, format='plain', refresh=False, wide=False): - # type: (Optional[List[str]], str, bool, bool) -> HandleCommandResult + @_cli_read_command('orch device ls') + def _list_devices(self, + hostname: Optional[List[str]] = None, + format: Format = Format.plain, + refresh: bool = False, + wide: bool = False) -> HandleCommandResult: """ - Provide information about storage devices present in cluster hosts - - Note: this does not have to be completely synchronous. Slightly out of - date hardware inventory is fine as long as hardware ultimately appears - in the output of this command. + List devices on a host """ + # Provide information about storage devices present in cluster hosts + # + # Note: this does not have to be completely synchronous. Slightly out of + # date hardware inventory is fine as long as hardware ultimately appears + # in the output of this command. nf = InventoryFilter(hosts=hostname) if hostname else None completion = self.get_inventory(host_filter=nf, refresh=refresh) @@ -411,8 +436,11 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule, self._orchestrator_wait([completion]) raise_if_exception(completion) - if format != 'plain': - return HandleCommandResult(stdout=to_format(completion.result, format, many=True, cls=InventoryHost)) + if format != Format.plain: + return HandleCommandResult(stdout=to_format(completion.result, + format, + many=True, + cls=InventoryHost)) else: display_map = { "Unsupported": "N/A", @@ -489,13 +517,11 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule, out.append(table.get_string()) return HandleCommandResult(stdout='\n'.join(out)) - @_cli_write_command( - 'orch device zap', - 'name=hostname,type=CephString ' - 'name=path,type=CephString ' - 'name=force,type=CephBool,req=false', - 'Zap (erase!) a device so it can be re-used') - def _zap_device(self, hostname, path, force=False): + @_cli_write_command('orch device zap') + def _zap_device(self, hostname: str, path: str, force: bool = False): + """ + Zap (erase!) a device so it can be re-used + """ if not force: raise OrchestratorError('must pass --force to PERMANENTLY ERASE DEVICE DATA') completion = self.zap_device(hostname, path) @@ -503,18 +529,19 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule, raise_if_exception(completion) return HandleCommandResult(stdout=completion.result_str()) - @_cli_read_command( - 'orch ls', - "name=service_type,type=CephString,req=false " - "name=service_name,type=CephString,req=false " - "name=export,type=CephBool,req=false " - "name=format,type=CephChoices,strings=plain|json|json-pretty|yaml,req=false " - "name=refresh,type=CephBool,req=false", - 'List services known to orchestrator') - def _list_services(self, host=None, service_type=None, service_name=None, export=False, format='plain', refresh=False): - - if export and format == 'plain': - format = 'yaml' + @_cli_read_command('orch ls') + def _list_services(self, + host: Optional[str] = None, + service_type: Optional[str] = None, + service_name: Optional[str] = None, + export: bool = False, + format: Format = Format.plain, + refresh: bool = False): + """ + List services known to orchestrator + """ + if export and format == Format.plain: + format = Format.yaml completion = self.describe_service(service_type, service_name, @@ -531,7 +558,7 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule, if len(services) == 0: return HandleCommandResult(stdout="No services reported") - elif format != 'plain': + elif format != Format.plain: if export: data = [s.spec for s in services] return HandleCommandResult(stdout=to_format(data, format, many=True, cls=ServiceSpec)) @@ -573,16 +600,17 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule, return HandleCommandResult(stdout=table.get_string()) - @_cli_read_command( - 'orch ps', - "name=hostname,type=CephString,req=false " - "name=service_name,type=CephString,req=false " - "name=daemon_type,type=CephString,req=false " - "name=daemon_id,type=CephString,req=false " - "name=format,type=CephChoices,strings=plain|json|json-pretty|yaml,req=false " - "name=refresh,type=CephBool,req=false", - 'List daemons known to orchestrator') - def _list_daemons(self, hostname=None, service_name=None, daemon_type=None, daemon_id=None, format='plain', refresh=False): + @_cli_read_command('orch ps') + def _list_daemons(self, + hostname: Optional[str] = None, + service_name: Optional[str] = None, + daemon_type: Optional[str] = None, + daemon_id: Optional[str] = None, + format: Format = Format.plain, + refresh: bool = False): + """ + List daemons known to orchestrator + """ completion = self.list_daemons(service_name, daemon_type, daemon_id=daemon_id, @@ -597,7 +625,7 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule, # Sort the list for display daemons.sort(key=lambda s: (ukn(s.daemon_type), ukn(s.hostname), ukn(s.daemon_id))) - if format != 'plain': + if format != Format.plain: return HandleCommandResult(stdout=to_format(daemons, format, many=True, cls=DaemonDescription)) else: if len(daemons) == 0: @@ -649,20 +677,17 @@ class OrchestratorCli(OrchestratorClientMixin, MgrModule, return HandleCommandResult(stdout=table.get_string()) - @_cli_write_command( - 'orch apply osd', - 'name=all_available_devices,type=CephBool,req=false ' - 'name=dry_run,type=CephBool,req=false ' - 'name=unmanaged,type=CephBool,req=false ' - "name=format,type=CephChoices,strings=plain|json|json-pretty|yaml,req=false", - 'Create OSD daemon(s) using a drive group spec') + @_cli_write_command('orch apply osd') def _apply_osd(self, all_available_devices: bool = False, - format: str = 'plain', - unmanaged=None, - dry_run=None, + format: Format = Format.plain, + unmanaged: Optional[bool] = None, + dry_run: bool = False, inbuf: Optional[str] = None) -> HandleCommandResult: - """Apply DriveGroupSpecs to create OSDs""" + """ + Create OSD daemon(s) using a drive group spec + """ + # Apply DriveGroupSpecs to create OSDs usage = """ usage: ceph orch apply osd -i [--dry-run] @@ -737,7 +762,7 @@ Examples: self._orchestrator_wait([completion]) raise_if_exception(completion) data = completion.result - if format == 'plain': + if format == Format.plain: out = generate_preview_tables(data, True) else: out = to_format(data, format, many=True, cls=None) @@ -764,7 +789,7 @@ Examples: completion = self.plan(dg_specs) self._orchestrator_wait([completion]) data = completion.result - if format == 'plain': + if format == Format.plain: out = generate_preview_tables(data, True) else: out = to_format(data, format, many=True, cls=None) @@ -772,13 +797,10 @@ Examples: return HandleCommandResult(-errno.EINVAL, stderr=usage) - @_cli_write_command( - 'orch daemon add osd', - "name=svc_arg,type=CephString,req=false", - 'Create an OSD service. Either --svc_arg=host:drives') - def _daemon_add_osd(self, svc_arg=None): - # type: (Optional[str]) -> HandleCommandResult - """Create one or more OSDs""" + @_cli_write_command('orch daemon add osd') + def _daemon_add_osd(self, svc_arg: Optional[str] = None) -> HandleCommandResult: + """Create an OSD service. Either --svc_arg=host:drives""" + # Create one or more OSDs""" usage = """ Usage: @@ -801,36 +823,28 @@ Usage: raise_if_exception(completion) return HandleCommandResult(stdout=completion.result_str()) - @_cli_write_command( - 'orch osd rm', - "name=svc_id,type=CephString,n=N " - "name=replace,type=CephBool,req=false " - "name=force,type=CephBool,req=false", - 'Remove OSD services') + @_cli_write_command('orch osd rm') def _osd_rm_start(self, svc_id: List[str], replace: bool = False, force: bool = False) -> HandleCommandResult: + """Remove OSD services""" completion = self.remove_osds(svc_id, replace=replace, force=force) self._orchestrator_wait([completion]) raise_if_exception(completion) return HandleCommandResult(stdout=completion.result_str()) - @_cli_write_command( - 'orch osd rm stop', - "name=svc_id,type=CephString,n=N", - 'Remove OSD services') + @_cli_write_command('orch osd rm stop') def _osd_rm_stop(self, svc_id: List[str]) -> HandleCommandResult: + """Remove OSD services""" completion = self.stop_remove_osds(svc_id) self._orchestrator_wait([completion]) raise_if_exception(completion) return HandleCommandResult(stdout=completion.result_str()) - @_cli_write_command( - 'orch osd rm status', - "name=format,type=CephChoices,strings=plain|json|json-pretty|yaml,req=false", - desc='status of OSD removal operation') - def _osd_rm_status(self, format='plain') -> HandleCommandResult: + @_cli_write_command('orch osd rm status') + def _osd_rm_status(self, format: Format = Format.plain) -> HandleCommandResult: + """status of OSD removal operation""" completion = self.remove_osds_status() self._orchestrator_wait([completion]) raise_if_exception(completion) @@ -839,7 +853,7 @@ Usage: if not report: return HandleCommandResult(stdout="No OSD remove/replace operations reported") - if format != 'plain': + if format != Format.plain: out = to_format(report, format, many=True, cls=None) else: table = PrettyTable( @@ -855,15 +869,12 @@ Usage: return HandleCommandResult(stdout=out) - @_cli_write_command( - 'orch daemon add', - 'name=daemon_type,type=CephChoices,strings=mon|mgr|rbd-mirror|crash|alertmanager|grafana|node-exporter|prometheus|cephadm-exporter,req=false ' - 'name=placement,type=CephString,req=false', - 'Add daemon(s)') + @_cli_write_command('orch daemon add') def _daemon_add_misc(self, - daemon_type: Optional[str] = None, + daemon_type: Optional[ServiceType] = None, placement: Optional[str] = None, inbuf: Optional[str] = None) -> HandleCommandResult: + """Add daemon(s)""" usage = f"""Usage: ceph orch daemon add -i ceph orch daemon add {daemon_type or ''} """ @@ -874,52 +885,48 @@ Usage: else: spec = PlacementSpec.from_string(placement) assert daemon_type - spec = ServiceSpec(daemon_type, placement=spec) - - daemon_type = spec.service_type + spec = ServiceSpec(daemon_type.value, placement=spec) - if daemon_type == 'mon': + if daemon_type == ServiceType.mon: completion = self.add_mon(spec) - elif daemon_type == 'mgr': + elif daemon_type == ServiceType.mgr: completion = self.add_mgr(spec) - elif daemon_type == 'rbd-mirror': + elif daemon_type == ServiceType.rbd_mirror: completion = self.add_rbd_mirror(spec) - elif daemon_type == 'crash': + elif daemon_type == ServiceType.crash: completion = self.add_crash(spec) - elif daemon_type == 'alertmanager': + elif daemon_type == ServiceType.alertmanager: completion = self.add_alertmanager(spec) - elif daemon_type == 'grafana': + elif daemon_type == ServiceType.grafana: completion = self.add_grafana(spec) - elif daemon_type == 'node-exporter': + elif daemon_type == ServiceType.node_exporter: completion = self.add_node_exporter(spec) - elif daemon_type == 'prometheus': + elif daemon_type == ServiceType.prometheus: completion = self.add_prometheus(spec) - elif daemon_type == 'mds': + elif daemon_type == ServiceType.mds: completion = self.add_mds(spec) - elif daemon_type == 'rgw': + elif daemon_type == ServiceType.rgw: completion = self.add_rgw(spec) - elif daemon_type == 'nfs': + elif daemon_type == ServiceType.nfs: completion = self.add_nfs(spec) - elif daemon_type == 'iscsi': + elif daemon_type == ServiceType.iscsi: completion = self.add_iscsi(spec) - elif daemon_type == 'cephadm-exporter': + elif daemon_type == ServiceType.cephadm_exporter: completion = self.add_cephadm_exporter(spec) else: - raise OrchestratorValidationError(f'unknown daemon type `{daemon_type}`') + tp = type(daemon_type) + raise OrchestratorValidationError(f'unknown daemon type `{tp}`') self._orchestrator_wait([completion]) raise_if_exception(completion) return HandleCommandResult(stdout=completion.result_str()) - @_cli_write_command( - 'orch daemon add mds', - 'name=fs_name,type=CephString ' - 'name=placement,type=CephString,req=false', - 'Start MDS daemon(s)') + @_cli_write_command('orch daemon add mds') def _mds_add(self, fs_name: str, placement: Optional[str] = None, inbuf: Optional[str] = None) -> HandleCommandResult: + """Start MDS daemon(s)""" if inbuf: raise OrchestratorValidationError('unrecognized command -i; -h or --help for usage') @@ -934,15 +941,7 @@ Usage: raise_if_exception(completion) return HandleCommandResult(stdout=completion.result_str()) - @_cli_write_command( - 'orch daemon add rgw', - 'name=realm_name,type=CephString ' - 'name=zone_name,type=CephString ' - 'name=subcluster,type=CephString,req=false ' - 'name=port,type=CephInt,req=false ' - 'name=ssl,type=CephBool,req=false ' - 'name=placement,type=CephString,req=false', - 'Start RGW daemon(s)') + @_cli_write_command('orch daemon add rgw') def _rgw_add(self, realm_name: str, zone_name: str, @@ -951,6 +950,7 @@ Usage: ssl: bool = False, placement: Optional[str] = None, inbuf: Optional[str] = None) -> HandleCommandResult: + """Start RGW daemon(s)""" if inbuf: raise OrchestratorValidationError('unrecognized command -i; -h or --help for usage') @@ -968,19 +968,14 @@ Usage: raise_if_exception(completion) return HandleCommandResult(stdout=completion.result_str()) - @_cli_write_command( - 'orch daemon add nfs', - "name=svc_id,type=CephString " - "name=pool,type=CephString " - "name=namespace,type=CephString,req=false " - 'name=placement,type=CephString,req=false', - 'Start NFS daemon(s)') + @_cli_write_command('orch daemon add nfs') def _nfs_add(self, svc_id: str, pool: str, namespace: Optional[str] = None, placement: Optional[str] = None, inbuf: Optional[str] = None) -> HandleCommandResult: + """Start NFS daemon(s)""" if inbuf: raise OrchestratorValidationError('unrecognized command -i; -h or --help for usage') @@ -996,14 +991,7 @@ Usage: raise_if_exception(completion) return HandleCommandResult(stdout=completion.result_str()) - @_cli_write_command( - 'orch daemon add iscsi', - 'name=pool,type=CephString ' - 'name=api_user,type=CephString ' - 'name=api_password,type=CephString ' - 'name=trusted_ip_list,type=CephString,req=false ' - 'name=placement,type=CephString,req=false', - 'Start iscsi daemon(s)') + @_cli_write_command('orch daemon add iscsi') def _iscsi_add(self, pool: str, api_user: str, @@ -1011,6 +999,7 @@ Usage: trusted_ip_list: Optional[str] = None, placement: Optional[str] = None, inbuf: Optional[str] = None) -> HandleCommandResult: + """Start iscsi daemon(s)""" if inbuf: raise OrchestratorValidationError('unrecognized command -i; -h or --help for usage') @@ -1028,36 +1017,27 @@ Usage: raise_if_exception(completion) return HandleCommandResult(stdout=completion.result_str()) - @_cli_write_command( - 'orch', - "name=action,type=CephChoices,strings=start|stop|restart|redeploy|reconfig " - "name=service_name,type=CephString", - 'Start, stop, restart, redeploy, or reconfig an entire service (i.e. all daemons)') - def _service_action(self, action, service_name): - completion = self.service_action(action, service_name) + @_cli_write_command('orch') + def _service_action(self, action: ServiceAction, service_name: str): + """Start, stop, restart, redeploy, or reconfig an entire service (i.e. all daemons)""" + completion = self.service_action(action.value, service_name) self._orchestrator_wait([completion]) raise_if_exception(completion) return HandleCommandResult(stdout=completion.result_str()) - @_cli_write_command( - 'orch daemon', - "name=action,type=CephChoices,strings=start|stop|restart|reconfig " - "name=name,type=CephString", - 'Start, stop, restart, (redeploy,) or reconfig a specific daemon') - def _daemon_action(self, action, name): + @_cli_write_command('orch daemon') + def _daemon_action(self, action: DaemonAction, name: str): + """Start, stop, restart, (redeploy,) or reconfig a specific daemon""" if '.' not in name: raise OrchestratorError('%s is not a valid daemon name' % name) - completion = self.daemon_action(action, name) + completion = self.daemon_action(action.value, name) self._orchestrator_wait([completion]) raise_if_exception(completion) return HandleCommandResult(stdout=completion.result_str()) - @_cli_write_command( - 'orch daemon redeploy', - "name=name,type=CephString " - "name=image,type=CephString,req=false", - 'Redeploy a daemon (with a specifc image)') + @_cli_write_command('orch daemon redeploy') def _daemon_action_redeploy(self, name: str, image: Optional[str] = None) -> HandleCommandResult: + """Redeploy a daemon (with a specifc image)""" if '.' not in name: raise OrchestratorError('%s is not a valid daemon name' % name) completion = self.daemon_action("redeploy", name, image=image) @@ -1065,12 +1045,11 @@ Usage: raise_if_exception(completion) return HandleCommandResult(stdout=completion.result_str()) - @_cli_write_command( - 'orch daemon rm', - "name=names,type=CephString,n=N " - 'name=force,type=CephBool,req=false', - 'Remove specific daemon(s)') - def _daemon_rm(self, names, force=False): + @_cli_write_command('orch daemon rm') + def _daemon_rm(self, + names: List[str], + force: Optional[bool] = False): + """Remove specific daemon(s)""" for name in names: if '.' not in name: raise OrchestratorError('%s is not a valid daemon name' % name) @@ -1083,12 +1062,11 @@ Usage: raise_if_exception(completion) return HandleCommandResult(stdout=completion.result_str()) - @_cli_write_command( - 'orch rm', - 'name=service_name,type=CephString ' - 'name=force,type=CephBool,req=false', - 'Remove a service') - def _service_rm(self, service_name, force=False): + @_cli_write_command('orch rm') + def _service_rm(self, + service_name: str, + force: bool = False): + """Remove a service""" if service_name in ['mon', 'mgr'] and not force: raise OrchestratorError('The mon and mgr services cannot be removed') completion = self.remove_service(service_name) @@ -1096,21 +1074,15 @@ Usage: raise_if_exception(completion) return HandleCommandResult(stdout=completion.result_str()) - @_cli_write_command( - 'orch apply', - 'name=service_type,type=CephChoices,strings=mon|mgr|rbd-mirror|crash|alertmanager|grafana|node-exporter|prometheus|cephadm-exporter,req=false ' - 'name=placement,type=CephString,req=false ' - 'name=dry_run,type=CephBool,req=false ' - 'name=format,type=CephChoices,strings=plain|json|json-pretty|yaml,req=false ' - 'name=unmanaged,type=CephBool,req=false', - 'Update the size or placement for a service or apply a large yaml spec') + @_cli_write_command('orch apply') def _apply_misc(self, - service_type: Optional[str] = None, + service_type: Optional[ServiceType] = None, placement: Optional[str] = None, dry_run: bool = False, - format: str = 'plain', + format: Format = Format.plain, unmanaged: bool = False, inbuf: Optional[str] = None) -> HandleCommandResult: + """Update the size or placement for a service or apply a large yaml spec""" usage = """Usage: ceph orch apply -i [--dry-run] ceph orch apply [--placement=] [--unmanaged] @@ -1128,7 +1100,7 @@ Usage: else: placementspec = PlacementSpec.from_string(placement) assert service_type - specs = [ServiceSpec(service_type, placement=placementspec, + specs = [ServiceSpec(service_type.value, placement=placementspec, unmanaged=unmanaged, preview_only=dry_run)] completion = self.apply(specs) @@ -1140,27 +1112,21 @@ Usage: self._orchestrator_wait([completion]) raise_if_exception(completion) data = completion.result - if format == 'plain': + if format == Format.plain: out = generate_preview_tables(data) else: out = to_format(data, format, many=True, cls=None) return HandleCommandResult(stdout=out) - @_cli_write_command( - 'orch apply mds', - 'name=fs_name,type=CephString ' - 'name=placement,type=CephString,req=false ' - 'name=dry_run,type=CephBool,req=false ' - 'name=unmanaged,type=CephBool,req=false ' - 'name=format,type=CephChoices,strings=plain|json|json-pretty|yaml,req=false', - 'Update the number of MDS instances for the given fs_name') + @_cli_write_command('orch apply mds') def _apply_mds(self, fs_name: str, placement: Optional[str] = None, dry_run: bool = False, unmanaged: bool = False, - format: str = 'plain', + format: Format = Format.plain, inbuf: Optional[str] = None) -> HandleCommandResult: + """Update the number of MDS instances for the given fs_name""" if inbuf: raise OrchestratorValidationError('unrecognized command -i; -h or --help for usage') @@ -1180,24 +1146,13 @@ Usage: self._orchestrator_wait([completion_plan]) raise_if_exception(completion_plan) data = completion_plan.result - if format == 'plain': + if format == Format.plain: out = preview_table_services(data) else: out = to_format(data, format, many=True, cls=None) return HandleCommandResult(stdout=out) - @_cli_write_command( - 'orch apply rgw', - 'name=realm_name,type=CephString ' - 'name=zone_name,type=CephString ' - 'name=subcluster,type=CephString,req=false ' - 'name=port,type=CephInt,req=false ' - 'name=ssl,type=CephBool,req=false ' - 'name=placement,type=CephString,req=false ' - 'name=dry_run,type=CephBool,req=false ' - 'name=format,type=CephChoices,strings=plain|json|json-pretty|yaml,req=false ' - 'name=unmanaged,type=CephBool,req=false', - 'Update the number of RGW instances for the given zone') + @_cli_write_command('orch apply rgw') def _apply_rgw(self, realm_name: str, zone_name: str, @@ -1206,9 +1161,10 @@ Usage: ssl: bool = False, placement: Optional[str] = None, dry_run: bool = False, - format: str = 'plain', + format: Format = Format.plain, unmanaged: bool = False, inbuf: Optional[str] = None) -> HandleCommandResult: + """Update the number of RGW instances for the given zone""" if inbuf: raise OrchestratorValidationError('unrecognized command -i; -h or --help for usage') @@ -1232,31 +1188,23 @@ Usage: self._orchestrator_wait([completion_plan]) raise_if_exception(completion_plan) data = completion_plan.result - if format == 'plain': + if format == Format.plain: out = preview_table_services(data) else: out = to_format(data, format, many=True, cls=None) return HandleCommandResult(stdout=out) - @_cli_write_command( - 'orch apply nfs', - 'name=svc_id,type=CephString ' - 'name=pool,type=CephString ' - 'name=namespace,type=CephString,req=false ' - 'name=placement,type=CephString,req=false ' - 'name=dry_run,type=CephBool,req=false ' - 'name=format,type=CephChoices,strings=plain|json|json-pretty|yaml,req=false ' - 'name=unmanaged,type=CephBool,req=false', - 'Scale an NFS service') + @_cli_write_command('orch apply nfs') def _apply_nfs(self, svc_id: str, pool: str, namespace: Optional[str] = None, placement: Optional[str] = None, - format: str = 'plain', + format: Format = Format.plain, dry_run: bool = False, unmanaged: bool = False, inbuf: Optional[str] = None) -> HandleCommandResult: + """Scale an NFS service""" if inbuf: raise OrchestratorValidationError('unrecognized command -i; -h or --help for usage') @@ -1278,23 +1226,13 @@ Usage: self._orchestrator_wait([completion_plan]) raise_if_exception(completion_plan) data = completion_plan.result - if format == 'plain': + if format == Format.plain: out = preview_table_services(data) else: out = to_format(data, format, many=True, cls=None) return HandleCommandResult(stdout=out) - @_cli_write_command( - 'orch apply iscsi', - 'name=pool,type=CephString ' - 'name=api_user,type=CephString ' - 'name=api_password,type=CephString ' - 'name=trusted_ip_list,type=CephString,req=false ' - 'name=placement,type=CephString,req=false ' - 'name=dry_run,type=CephBool,req=false ' - 'name=format,type=CephChoices,strings=plain|json|json-pretty|yaml,req=false ' - 'name=unmanaged,type=CephBool,req=false', - 'Scale an iSCSI service') + @_cli_write_command('orch apply iscsi') def _apply_iscsi(self, pool: str, api_user: str, @@ -1303,8 +1241,9 @@ Usage: placement: Optional[str] = None, unmanaged: bool = False, dry_run: bool = False, - format: str = 'plain', + format: Format = Format.plain, inbuf: Optional[str] = None) -> HandleCommandResult: + """Scale an iSCSI service""" if inbuf: raise OrchestratorValidationError('unrecognized command -i; -h or --help for usage') @@ -1328,25 +1267,23 @@ Usage: self._orchestrator_wait([completion_plan]) raise_if_exception(completion_plan) data = completion_plan.result - if format == 'plain': + if format == Format.plain: out = preview_table_services(data) else: out = to_format(data, format, many=True, cls=None) return HandleCommandResult(stdout=out) - @_cli_write_command( - 'orch set backend', - "name=module_name,type=CephString,req=true", - 'Select orchestrator module backend') - def _set_backend(self, module_name): + @_cli_write_command('orch set backend') + def _set_backend(self, module_name: Optional[str] = None): """ - We implement a setter command instead of just having the user - modify the setting directly, so that we can validate they're setting - it to a module that really exists and is enabled. - - There isn't a mechanism for ensuring they don't *disable* the module - later, but this is better than nothing. + Select orchestrator module backend """ + # We implement a setter command instead of just having the user + # modify the setting directly, so that we can validate they're setting + # it to a module that really exists and is enabled. + + # There isn't a mechanism for ensuring they don't *disable* the module + # later, but this is better than nothing. mgr_map = self.get("mgr_map") if module_name is None or module_name == "": @@ -1383,35 +1320,31 @@ Usage: return HandleCommandResult(-errno.EINVAL, stderr="Module '{0}' not found".format(module_name)) - @_cli_write_command( - 'orch pause', - desc='Pause orchestrator background work') + @_cli_write_command('orch pause') def _pause(self): + """Pause orchestrator background work""" self.pause() return HandleCommandResult() - @_cli_write_command( - 'orch resume', - desc='Resume orchestrator background work (if paused)') + @_cli_write_command('orch resume') def _resume(self): + """Resume orchestrator background work (if paused)""" self.resume() return HandleCommandResult() - @_cli_write_command( - 'orch cancel', - desc='cancels ongoing operations') + @_cli_write_command('orch cancel') def _cancel(self): """ + cancels ongoing operations + ProgressReferences might get stuck. Let's unstuck them. """ self.cancel_completions() return HandleCommandResult() - @_cli_read_command( - 'orch status', - 'name=format,type=CephChoices,strings=plain|json|json-pretty|yaml,req=false', - desc='Report configured backend and its status') - def _status(self, format='plain'): + @_cli_read_command('orch status') + def _status(self, format: Format = Format.plain): + """Report configured backend and its status""" o = self._select_orchestrator() if o is None: raise NoOrchestrator() @@ -1425,7 +1358,7 @@ Usage: if not avail: result['reason'] = why - if format != 'plain': + if format != Format.plain: output = to_format(result, format, many=False, cls=None) else: output = "Backend: {0}".format(result['backend']) @@ -1473,22 +1406,20 @@ Usage: f" Maybe you meant `--ceph-version {ver}`?" raise OrchestratorValidationError(s) - @_cli_write_command( - 'orch upgrade check', - 'name=image,type=CephString,req=false ' - 'name=ceph_version,type=CephString,req=false', - desc='Check service versions vs available and target containers') - def _upgrade_check(self, image=None, ceph_version=None): + @_cli_write_command('orch upgrade check') + def _upgrade_check(self, + image: Optional[str] = None, + ceph_version: Optional[str] = None): + """Check service versions vs available and target containers""" self._upgrade_check_image_name(image, ceph_version) completion = self.upgrade_check(image=image, version=ceph_version) self._orchestrator_wait([completion]) raise_if_exception(completion) return HandleCommandResult(stdout=completion.result_str()) - @_cli_write_command( - 'orch upgrade status', - desc='Check service versions vs available and target containers') + @_cli_write_command('orch upgrade status') def _upgrade_status(self): + """Check service versions vs available and target containers""" completion = self.upgrade_status() self._orchestrator_wait([completion]) raise_if_exception(completion) @@ -1501,40 +1432,36 @@ Usage: out = json.dumps(r, indent=4) return HandleCommandResult(stdout=out) - @_cli_write_command( - 'orch upgrade start', - 'name=image,type=CephString,req=false ' - 'name=ceph_version,type=CephString,req=false', - desc='Initiate upgrade') - def _upgrade_start(self, image=None, ceph_version=None): + @_cli_write_command('orch upgrade start') + def _upgrade_start(self, + image: Optional[str] = None, + ceph_version: Optional[str] = None): + """Initiate upgrade""" self._upgrade_check_image_name(image, ceph_version) completion = self.upgrade_start(image, ceph_version) self._orchestrator_wait([completion]) raise_if_exception(completion) return HandleCommandResult(stdout=completion.result_str()) - @_cli_write_command( - 'orch upgrade pause', - desc='Pause an in-progress upgrade') + @_cli_write_command('orch upgrade pause') def _upgrade_pause(self): + """Pause an in-progress upgrade""" completion = self.upgrade_pause() self._orchestrator_wait([completion]) raise_if_exception(completion) return HandleCommandResult(stdout=completion.result_str()) - @_cli_write_command( - 'orch upgrade resume', - desc='Resume paused upgrade') + @_cli_write_command('orch upgrade resume') def _upgrade_resume(self): + """Resume paused upgrade""" completion = self.upgrade_resume() self._orchestrator_wait([completion]) raise_if_exception(completion) return HandleCommandResult(stdout=completion.result_str()) - @_cli_write_command( - 'orch upgrade stop', - desc='Stop an in-progress upgrade') + @_cli_write_command('orch upgrade stop') def _upgrade_stop(self): + """Stop an in-progress upgrade""" completion = self.upgrade_stop() self._orchestrator_wait([completion]) raise_if_exception(completion) diff --git a/src/pybind/mgr/orchestrator/tests/test_orchestrator.py b/src/pybind/mgr/orchestrator/tests/test_orchestrator.py index c5858aa9531..0f456d7c711 100644 --- a/src/pybind/mgr/orchestrator/tests/test_orchestrator.py +++ b/src/pybind/mgr/orchestrator/tests/test_orchestrator.py @@ -16,7 +16,7 @@ from tests import mock from orchestrator import raise_if_exception, Completion, ProgressReference from orchestrator import InventoryHost, DaemonDescription, ServiceDescription from orchestrator import OrchestratorValidationError -from orchestrator.module import to_format, OrchestratorCli, preview_table_osd +from orchestrator.module import to_format, Format, OrchestratorCli, preview_table_osd def _test_resource(data, resource_class, extra=None): @@ -281,11 +281,11 @@ events: data = yaml.safe_load(y) object = cls.from_json(data) - assert to_format(object, 'yaml', False, cls) == y - assert to_format([object], 'yaml', True, cls) == y + assert to_format(object, Format.yaml, False, cls) == y + assert to_format([object], Format.yaml, True, cls) == y - j = json.loads(to_format(object, 'json', False, cls)) - assert to_format(cls.from_json(j), 'yaml', False, cls) == y + j = json.loads(to_format(object, Format.json, False, cls)) + assert to_format(cls.from_json(j), Format.yaml, False, cls) == y def test_event_multiline():