Skip to content

Commit 70afb7b

Browse files
mgr/nfs: Add Monitoring_Addr parameter to ganesha.conf
Fixes: https://tracker.ceph.com/issues/71031 Signed-off-by: Shweta Bhosale <[email protected]>
1 parent 9abd01f commit 70afb7b

File tree

7 files changed

+90
-3
lines changed

7 files changed

+90
-3
lines changed

doc/cephadm/services/nfs.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,24 @@ Alternatively, an NFS service can be applied using a YAML specification.
4949
- host2
5050
spec:
5151
port: 12345
52+
monitoring_port: 567
53+
monitoring_ip_addrs:
54+
host1: 10.0.0.123
55+
host2: 10.0.0.124
56+
monitoring_networks:
57+
- 192.168.124.0/24
58+
5259
5360
In this example, we run the server on the non-default ``port`` of
5461
12345 (instead of the default 2049) on ``host1`` and ``host2``.
62+
The default monitoring port can be customized using the ``monitoring_port``
63+
parameter. Additionally, you can specify the ``monitoring_ip_addrs`` or
64+
``monitoring_networks`` parameters to bind the monitoring port to a specific
65+
IP address or network. If ``monitoring_ip_addrs`` is provided and the specified
66+
IP address is assigned to the host, that IP address will be used. If the IP
67+
address is not present and ``monitoring_networks`` is specified, an IP address
68+
that matches one of the specified networks will be used. If neither condition
69+
is met, the default binding will happen on all available network interfaces.
5570

5671
The specification can then be applied by running the following command:
5772

src/pybind/mgr/cephadm/inventory.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1597,6 +1597,14 @@ def get_scheduled_daemon_action(self, host: str, daemon: str) -> Optional[str]:
15971597

15981598
return self.scheduled_daemon_actions.get(host, {}).get(daemon)
15991599

1600+
def get_host_network_ips(self, host: str) -> List[str]:
1601+
return [
1602+
ip
1603+
for net_details in self.networks.get(host, {}).values()
1604+
for ips in net_details.values()
1605+
for ip in ips
1606+
]
1607+
16001608

16011609
class NodeProxyCache:
16021610
def __init__(self, mgr: 'CephadmOrchestrator') -> None:

src/pybind/mgr/cephadm/module.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,8 +1068,14 @@ def update_failed_daemon_health_check(self) -> None:
10681068
self.set_health_warning('CEPHADM_FAILED_DAEMON', f'{len(failed_daemons)} failed cephadm daemon(s)', len(
10691069
failed_daemons), failed_daemons)
10701070

1071-
def get_first_matching_network_ip(self, host: str, sspec: ServiceSpec) -> Optional[str]:
1072-
sspec_networks = sspec.networks
1071+
def get_first_matching_network_ip(
1072+
self,
1073+
host: str,
1074+
sspec: ServiceSpec,
1075+
sspec_networks: Optional[List[str]] = None
1076+
) -> Optional[str]:
1077+
if not sspec_networks:
1078+
sspec_networks = sspec.networks
10731079
for subnet, ifaces in self.cache.networks.get(host, {}).items():
10741080
host_network = ipaddress.ip_network(subnet)
10751081
for spec_network_str in sspec_networks:

src/pybind/mgr/cephadm/services/nfs.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ def generate_config(self, daemon_spec: CephadmDaemonDeploySpec) -> Tuple[Dict[st
9898
self.create_rados_config_obj(spec)
9999

100100
port = daemon_spec.ports[0] if daemon_spec.ports else 2049
101+
monitoring_port = spec.monitoring_port if spec.monitoring_port else 9587
101102

102103
# create the RGW keyring
103104
rgw_user = f'{rados_user}-rgw'
@@ -112,6 +113,18 @@ def generate_config(self, daemon_spec: CephadmDaemonDeploySpec) -> Tuple[Dict[st
112113
else:
113114
logger.debug("using haproxy bind address: %r", bind_addr)
114115

116+
# check if monitor needs to be bind on specific ip
117+
monitoring_addr = spec.monitoring_ip_addrs.get(host) if spec.monitoring_ip_addrs else None
118+
if monitoring_addr and monitoring_addr not in self.mgr.cache.get_host_network_ips(host):
119+
logger.debug(f"Monitoring IP {monitoring_addr} is not configured on host {daemon_spec.host}.")
120+
monitoring_addr = None
121+
if not monitoring_addr and spec.monitoring_networks:
122+
monitoring_addr = self.mgr.get_first_matching_network_ip(daemon_spec.host, spec, spec.monitoring_networks)
123+
if not monitoring_addr:
124+
logger.debug(f"No IP address found in the network {spec.monitoring_networks} on host {daemon_spec.host}.")
125+
if monitoring_addr:
126+
daemon_spec.port_ips.update({str(monitoring_port): monitoring_addr})
127+
115128
# generate the ganesha config
116129
def get_ganesha_conf() -> str:
117130
context: Dict[str, Any] = {
@@ -123,7 +136,8 @@ def get_ganesha_conf() -> str:
123136
"url": f'rados://{POOL_NAME}/{spec.service_id}/{spec.rados_config_name()}',
124137
# fall back to default NFS port if not present in daemon_spec
125138
"port": port,
126-
"monitoring_port": spec.monitoring_port if spec.monitoring_port else 9587,
139+
"monitoring_addr": monitoring_addr,
140+
"monitoring_port": monitoring_port,
127141
"bind_addr": bind_addr,
128142
"haproxy_hosts": [],
129143
"nfs_idmap_conf": nfs_idmap_conf,

src/pybind/mgr/cephadm/templates/services/nfs/ganesha.conf.j2

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ NFS_CORE_PARAM {
1212
{% endif %}
1313
{% if haproxy_hosts %}
1414
HAProxy_Hosts = {{ haproxy_hosts|join(", ") }};
15+
{% endif %}
16+
{% if monitoring_addr %}
17+
Monitoring_Addr = {{ monitoring_addr }};
1518
{% endif %}
1619
Monitoring_Port = {{ monitoring_port }};
1720
}

src/pybind/mgr/cephadm/tests/test_services.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3225,6 +3225,37 @@ def test_keepalive_only_nfs_config(self, _run_cephadm, cephadm_module: CephadmOr
32253225
# check keepalived config
32263226
assert keepalived_generated_conf[0] == keepalived_expected_conf
32273227

3228+
@patch("cephadm.serve.CephadmServe._run_cephadm")
3229+
@patch("cephadm.services.nfs.NFSService.fence_old_ranks", MagicMock())
3230+
@patch("cephadm.services.nfs.NFSService.run_grace_tool", MagicMock())
3231+
@patch("cephadm.services.nfs.NFSService.purge", MagicMock())
3232+
@patch("cephadm.services.nfs.NFSService.create_rados_config_obj", MagicMock())
3233+
def test_nfs_config_monitoring_ip(self, _run_cephadm, cephadm_module: CephadmOrchestrator):
3234+
_run_cephadm.side_effect = async_side_effect(('{}', '', 0))
3235+
3236+
with with_host(cephadm_module, 'test', addr='1.2.3.7'):
3237+
cephadm_module.cache.update_host_networks('test', {
3238+
'1.2.3.0/24': {
3239+
'if0': ['1.2.3.1']
3240+
}
3241+
})
3242+
3243+
nfs_spec = NFSServiceSpec(service_id="foo", placement=PlacementSpec(hosts=['test']),
3244+
monitoring_ip_addrs={'test': '1.2.3.1'})
3245+
with with_service(cephadm_module, nfs_spec) as _:
3246+
nfs_generated_conf, _ = service_registry.get_service('nfs').generate_config(
3247+
CephadmDaemonDeploySpec(host='test', daemon_id='foo.test.0.0', service_name=nfs_spec.service_name()))
3248+
ganesha_conf = nfs_generated_conf['files']['ganesha.conf']
3249+
assert "Monitoring_Addr = 1.2.3.1" in ganesha_conf
3250+
3251+
nfs_spec = NFSServiceSpec(service_id="foo", placement=PlacementSpec(hosts=['test']),
3252+
monitoring_networks=['1.2.3.0/24'])
3253+
with with_service(cephadm_module, nfs_spec) as _:
3254+
nfs_generated_conf, _ = service_registry.get_service('nfs').generate_config(
3255+
CephadmDaemonDeploySpec(host='test', daemon_id='foo.test.0.0', service_name=nfs_spec.service_name()))
3256+
ganesha_conf = nfs_generated_conf['files']['ganesha.conf']
3257+
assert "Monitoring_Addr = 1.2.3.1" in ganesha_conf
3258+
32283259
@patch("cephadm.services.nfs.NFSService.fence_old_ranks", MagicMock())
32293260
@patch("cephadm.services.nfs.NFSService.run_grace_tool", MagicMock())
32303261
@patch("cephadm.services.nfs.NFSService.purge", MagicMock())

src/python-common/ceph/deployment/service_spec.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,6 +1141,8 @@ def __init__(self,
11411141
config: Optional[Dict[str, str]] = None,
11421142
networks: Optional[List[str]] = None,
11431143
port: Optional[int] = None,
1144+
monitoring_networks: Optional[List[str]] = None,
1145+
monitoring_ip_addrs: Optional[Dict[str, str]] = None,
11441146
monitoring_port: Optional[int] = None,
11451147
virtual_ip: Optional[str] = None,
11461148
enable_nlm: bool = False,
@@ -1158,7 +1160,15 @@ def __init__(self,
11581160
extra_entrypoint_args=extra_entrypoint_args, custom_configs=custom_configs)
11591161

11601162
self.port = port
1163+
1164+
# monitoring_ip_addrs is a dictionary where each key is a hostname and the corresponding
1165+
# value is the IP address {hostname: ip} that the monitor should bind to on that host.
1166+
# monitoring_networks is a list of networks where the monitor is allowed to bind.
1167+
# user can pass one parameter to bind monitor on specific IP.
1168+
self.monitoring_ip_addrs = monitoring_ip_addrs
1169+
self.monitoring_networks = monitoring_networks
11611170
self.monitoring_port = monitoring_port
1171+
11621172
self.virtual_ip = virtual_ip
11631173
self.enable_haproxy_protocol = enable_haproxy_protocol
11641174
self.idmap_conf = idmap_conf

0 commit comments

Comments
 (0)