From 6b852c2e013566b252ada9c33a7865a4cb62d23e Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 23 Feb 2021 13:47:59 -0500 Subject: [PATCH] mgr/cephadm: add config section to ServiceSpec Signed-off-by: Sage Weil --- src/pybind/mgr/cephadm/serve.py | 33 +++++++++++++++++++ .../ceph/deployment/service_spec.py | 32 +++++++++++++----- 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/src/pybind/mgr/cephadm/serve.py b/src/pybind/mgr/cephadm/serve.py index 927bcaee19114..ee21e1cd9b7be 100644 --- a/src/pybind/mgr/cephadm/serve.py +++ b/src/pybind/mgr/cephadm/serve.py @@ -25,6 +25,9 @@ from cephadm.services.cephadmservice import CephadmDaemonDeploySpec from cephadm.schedule import HostAssignment from cephadm.utils import forall_hosts, cephadmNoImage, is_repo_digest, \ CephadmNoImage, CEPH_UPGRADE_ORDER, ContainerInspectInfo +from mgr_module import MonCommandFailed + +from . import utils if TYPE_CHECKING: from cephadm.module import CephadmOrchestrator @@ -448,6 +451,34 @@ class CephadmServe: return r + def _apply_service_config(self, spec: ServiceSpec) -> None: + if spec.config: + section = utils.name_to_config_section(spec.service_name()) + for k, v in spec.config.items(): + try: + current = self.mgr.get_foreign_ceph_option(section, k) + except KeyError: + self.log.warning( + f'Ignoring invalid {spec.service_name()} config option {k}' + ) + self.mgr.events.for_service( + spec, OrchestratorEvent.ERROR, f'Invalid config option {k}' + ) + continue + if current != v: + self.log.debug(f'setting [{section}] {k} = {v}') + try: + self.mgr.check_mon_command({ + 'prefix': 'config set', + 'name': k, + 'value': str(v), + 'who': section, + }) + except MonCommandFailed as e: + self.log.warning( + f'Failed to set {spec.service_name()} option {k}: {e}' + ) + def _apply_service(self, spec: ServiceSpec) -> bool: """ Schedule a service. Deploy new daemons or remove old ones, depending @@ -465,6 +496,8 @@ class CephadmServe: return False self.log.debug('Applying service %s spec' % service_name) + self._apply_service_config(spec) + if service_type == 'osd': self.mgr.osd_service.create_from_spec(cast(DriveGroupSpec, spec)) # TODO: return True would result in a busy loop diff --git a/src/python-common/ceph/deployment/service_spec.py b/src/python-common/ceph/deployment/service_spec.py index 68b456393e6ab..dde78ac4101a7 100644 --- a/src/python-common/ceph/deployment/service_spec.py +++ b/src/python-common/ceph/deployment/service_spec.py @@ -429,6 +429,7 @@ class ServiceSpec(object): service_id: Optional[str] = None, placement: Optional[PlacementSpec] = None, count: Optional[int] = None, + config: Optional[Dict[str, str]] = None, unmanaged: bool = False, preview_only: bool = False, ): @@ -442,6 +443,10 @@ class ServiceSpec(object): self.unmanaged = unmanaged self.preview_only = preview_only + self.config: Optional[Dict[str, str]] = None + if config: + self.config = {k.replace(' ', '_'): v for k, v in config.items()} + @classmethod @handle_type_error def from_json(cls: Type[ServiceSpecT], json_spec: Dict) -> ServiceSpecT: @@ -465,6 +470,8 @@ class ServiceSpec(object): service_type: nfs service_id: foo + config: + some_option: the_value spec: pool: mypool namespace: myns @@ -584,12 +591,14 @@ class NFSServiceSpec(ServiceSpec): namespace: Optional[str] = None, placement: Optional[PlacementSpec] = None, unmanaged: bool = False, - preview_only: bool = False + preview_only: bool = False, + config: Optional[Dict[str, str]] = None, ): assert service_type == 'nfs' super(NFSServiceSpec, self).__init__( 'nfs', service_id=service_id, - placement=placement, unmanaged=unmanaged, preview_only=preview_only) + placement=placement, unmanaged=unmanaged, preview_only=preview_only, + config=config) #: RADOS pool where NFS client recovery data is stored. self.pool = pool @@ -640,6 +649,7 @@ class RGWSpec(ServiceSpec): unmanaged: bool = False, ssl: bool = False, preview_only: bool = False, + config: Optional[Dict[str, str]] = None, ): assert service_type == 'rgw', service_type if service_id: @@ -657,7 +667,7 @@ class RGWSpec(ServiceSpec): super(RGWSpec, self).__init__( 'rgw', service_id=service_id, placement=placement, unmanaged=unmanaged, - preview_only=preview_only) + preview_only=preview_only, config=config) self.rgw_realm = rgw_realm self.rgw_zone = rgw_zone @@ -713,12 +723,14 @@ class IscsiServiceSpec(ServiceSpec): ssl_key: Optional[str] = None, placement: Optional[PlacementSpec] = None, unmanaged: bool = False, - preview_only: bool = False + preview_only: bool = False, + config: Optional[Dict[str, str]] = None, ): assert service_type == 'iscsi' super(IscsiServiceSpec, self).__init__('iscsi', service_id=service_id, placement=placement, unmanaged=unmanaged, - preview_only=preview_only) + preview_only=preview_only, + config=config) #: RADOS pool where ceph-iscsi config data is stored. self.pool = pool @@ -758,12 +770,13 @@ class AlertManagerSpec(ServiceSpec): unmanaged: bool = False, preview_only: bool = False, user_data: Optional[Dict[str, Any]] = None, + config: Optional[Dict[str, str]] = None, ): assert service_type == 'alertmanager' super(AlertManagerSpec, self).__init__( 'alertmanager', service_id=service_id, placement=placement, unmanaged=unmanaged, - preview_only=preview_only) + preview_only=preview_only, config=config) # Custom configuration. # @@ -789,6 +802,7 @@ class HA_RGWSpec(ServiceSpec): def __init__(self, service_type: str = 'ha-rgw', service_id: Optional[str] = None, + config: Optional[Dict[str, str]] = None, placement: Optional[PlacementSpec] = None, virtual_ip_interface: Optional[str] = None, virtual_ip_address: Optional[str] = None, @@ -810,7 +824,8 @@ class HA_RGWSpec(ServiceSpec): definitive_host_list: Optional[List[HostPlacementSpec]] = None ): assert service_type == 'ha-rgw' - super(HA_RGWSpec, self).__init__('ha-rgw', service_id=service_id, placement=placement) + super(HA_RGWSpec, self).__init__('ha-rgw', service_id=service_id, + placement=placement, config=config) self.virtual_ip_interface = virtual_ip_interface self.virtual_ip_address = virtual_ip_address @@ -878,6 +893,7 @@ class CustomContainerSpec(ServiceSpec): def __init__(self, service_type: str = 'container', service_id: Optional[str] = None, + config: Optional[Dict[str, str]] = None, placement: Optional[PlacementSpec] = None, unmanaged: bool = False, preview_only: bool = False, @@ -901,7 +917,7 @@ class CustomContainerSpec(ServiceSpec): super(CustomContainerSpec, self).__init__( service_type, service_id, placement=placement, unmanaged=unmanaged, - preview_only=preview_only) + preview_only=preview_only, config=config) self.image = image self.entrypoint = entrypoint -- 2.39.5