Problem: ceph mgr fail or active ceph mgr restart causes unnecessary client files recreation on _admin hosts. Files such as /etc/ceph/ceph.conf and /etc/ceph/ceph.client.admin.keyring are rewritten even when their content has not changed.
Root cause:
update_client_file() stores client file metadata as a Python tuple (digest, mode, uid, gid).
When save_host() persists this to the mon store via json.dumps(), the tuple is serialized as a JSON array since JSON has no tuple type.
On mgr failover or restart, cache.load() deserializes the data with json.loads(), which returns a Python list instead of a tuple.
The comparison in _write_client_files(): match = old_files[path] == (digest, mode, uid, gid) then compares a list (from JSON) against a tuple (freshly built), which always evaluates to False.
This causes every client file to be rewritten on every mgr failover or restart.
Code Fixes:
1. src/pybind/mgr/cephadm/inventory.py:
convert the deserialized lists back to tuples when loading last_client_files
Fixes: https://tracker.ceph.com/issues/76176
Signed-off-by: Yael Azulay <yazulay@redhat.com>
self.devices[host] += self.load_host_devices(host)
self.networks[host] = j.get('networks_and_interfaces', {})
self.osdspec_previews[host] = j.get('osdspec_previews', {})
- self.last_client_files[host] = j.get('last_client_files', {})
+ self.last_client_files[host] = {
+ path: tuple(v) for path, v in j.get('last_client_files', {}).items()
+ }
for name, ts in j.get('osdspec_last_applied', {}).items():
self.osdspec_last_applied[host][name] = str_to_datetime(ts)