summaryrefslogtreecommitdiffstats
path: root/src/pybind/mgr/cephadm/tuned_profiles.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/pybind/mgr/cephadm/tuned_profiles.py')
-rw-r--r--src/pybind/mgr/cephadm/tuned_profiles.py103
1 files changed, 103 insertions, 0 deletions
diff --git a/src/pybind/mgr/cephadm/tuned_profiles.py b/src/pybind/mgr/cephadm/tuned_profiles.py
new file mode 100644
index 000000000..8ec30bd53
--- /dev/null
+++ b/src/pybind/mgr/cephadm/tuned_profiles.py
@@ -0,0 +1,103 @@
+import logging
+from typing import Dict, List, TYPE_CHECKING
+from ceph.utils import datetime_now
+from .schedule import HostAssignment
+from ceph.deployment.service_spec import ServiceSpec, TunedProfileSpec
+
+if TYPE_CHECKING:
+ from cephadm.module import CephadmOrchestrator
+
+logger = logging.getLogger(__name__)
+
+SYSCTL_DIR = '/etc/sysctl.d'
+
+
+class TunedProfileUtils():
+ def __init__(self, mgr: "CephadmOrchestrator") -> None:
+ self.mgr = mgr
+
+ def _profile_to_str(self, p: TunedProfileSpec) -> str:
+ p_str = f'# created by cephadm\n# tuned profile "{p.profile_name}"\n\n'
+ for k, v in p.settings.items():
+ p_str += f'{k} = {v}\n'
+ return p_str
+
+ def _write_all_tuned_profiles(self) -> None:
+ host_profile_mapping: Dict[str, List[Dict[str, str]]] = {}
+ for host in self.mgr.cache.get_hosts():
+ host_profile_mapping[host] = []
+
+ for profile in self.mgr.tuned_profiles.list_profiles():
+ p_str = self._profile_to_str(profile)
+ ha = HostAssignment(
+ spec=ServiceSpec(
+ 'crash', placement=profile.placement),
+ hosts=self.mgr.cache.get_schedulable_hosts(),
+ unreachable_hosts=self.mgr.cache.get_unreachable_hosts(),
+ draining_hosts=self.mgr.cache.get_draining_hosts(),
+ daemons=[],
+ networks=self.mgr.cache.networks,
+ )
+ all_slots, _, _ = ha.place()
+ for host in {s.hostname for s in all_slots}:
+ host_profile_mapping[host].append({profile.profile_name: p_str})
+
+ for host, profiles in host_profile_mapping.items():
+ self._remove_stray_tuned_profiles(host, profiles)
+ self._write_tuned_profiles(host, profiles)
+
+ def _remove_stray_tuned_profiles(self, host: str, profiles: List[Dict[str, str]]) -> None:
+ """
+ this function looks at the contents of /etc/sysctl.d/ for profiles we have written
+ that should now be removed. It assumes any file with "-cephadm-tuned-profile.conf" in
+ it is written by us any without that are not. Only files written by us are considered
+ candidates for removal. The "profiles" parameter is a list of dictionaries that map
+ profile names to the file contents to actually be written to the
+ /etc/sysctl.d/<profile-name>-cephadm-tuned-profile.conf. For example
+ [
+ {
+ 'profile1': 'setting1: value1\nsetting2: value2'
+ },
+ {
+ 'profile2': 'setting3: value3'
+ }
+ ]
+ what we want to end up doing is going through the keys of the dicts and appending
+ -cephadm-tuned-profile.conf to the profile names to build our list of profile files that
+ SHOULD be on the host. Then if we see any file names that don't match this, but
+ DO include "-cephadm-tuned-profile.conf" (implying they're from us), remove them.
+ """
+ if self.mgr.cache.is_host_unreachable(host):
+ return
+ cmd = ['ls', SYSCTL_DIR]
+ found_files = self.mgr.ssh.check_execute_command(host, cmd, log_command=self.mgr.log_refresh_metadata).split('\n')
+ found_files = [s.strip() for s in found_files]
+ profile_names: List[str] = sum([[*p] for p in profiles], []) # extract all profiles names
+ profile_names = list(set(profile_names)) # remove duplicates
+ expected_files = [p + '-cephadm-tuned-profile.conf' for p in profile_names]
+ updated = False
+ for file in found_files:
+ if '-cephadm-tuned-profile.conf' not in file:
+ continue
+ if file not in expected_files:
+ logger.info(f'Removing stray tuned profile file {file}')
+ cmd = ['rm', '-f', f'{SYSCTL_DIR}/{file}']
+ self.mgr.ssh.check_execute_command(host, cmd)
+ updated = True
+ if updated:
+ self.mgr.ssh.check_execute_command(host, ['sysctl', '--system'])
+
+ def _write_tuned_profiles(self, host: str, profiles: List[Dict[str, str]]) -> None:
+ if self.mgr.cache.is_host_unreachable(host):
+ return
+ updated = False
+ for p in profiles:
+ for profile_name, content in p.items():
+ if self.mgr.cache.host_needs_tuned_profile_update(host, profile_name):
+ logger.info(f'Writing tuned profile {profile_name} to host {host}')
+ profile_filename: str = f'{SYSCTL_DIR}/{profile_name}-cephadm-tuned-profile.conf'
+ self.mgr.ssh.write_remote_file(host, profile_filename, content.encode('utf-8'))
+ updated = True
+ if updated:
+ self.mgr.ssh.check_execute_command(host, ['sysctl', '--system'])
+ self.mgr.cache.last_tuned_profile_update[host] = datetime_now()