]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/cephadm/tuned_profiles.py
import ceph quincy 17.2.6
[ceph.git] / ceph / src / pybind / mgr / cephadm / tuned_profiles.py
1 import logging
2 from typing import Dict, List, TYPE_CHECKING
3 from ceph.utils import datetime_now
4 from .schedule import HostAssignment
5 from ceph.deployment.service_spec import ServiceSpec, TunedProfileSpec
6
7 if TYPE_CHECKING:
8 from cephadm.module import CephadmOrchestrator
9
10 logger = logging.getLogger(__name__)
11
12 SYSCTL_DIR = '/etc/sysctl.d'
13
14
15 class TunedProfileUtils():
16 def __init__(self, mgr: "CephadmOrchestrator") -> None:
17 self.mgr = mgr
18
19 def _profile_to_str(self, p: TunedProfileSpec) -> str:
20 p_str = f'# created by cephadm\n# tuned profile "{p.profile_name}"\n\n'
21 for k, v in p.settings.items():
22 p_str += f'{k} = {v}\n'
23 return p_str
24
25 def _write_all_tuned_profiles(self) -> None:
26 host_profile_mapping: Dict[str, List[Dict[str, str]]] = {}
27 for host in self.mgr.cache.get_hosts():
28 host_profile_mapping[host] = []
29
30 for profile in self.mgr.tuned_profiles.list_profiles():
31 p_str = self._profile_to_str(profile)
32 ha = HostAssignment(
33 spec=ServiceSpec(
34 'crash', placement=profile.placement),
35 hosts=self.mgr.cache.get_schedulable_hosts(),
36 unreachable_hosts=self.mgr.cache.get_unreachable_hosts(),
37 draining_hosts=self.mgr.cache.get_draining_hosts(),
38 daemons=[],
39 networks=self.mgr.cache.networks,
40 )
41 all_slots, _, _ = ha.place()
42 for host in {s.hostname for s in all_slots}:
43 host_profile_mapping[host].append({profile.profile_name: p_str})
44
45 for host, profiles in host_profile_mapping.items():
46 self._remove_stray_tuned_profiles(host, profiles)
47 self._write_tuned_profiles(host, profiles)
48
49 def _remove_stray_tuned_profiles(self, host: str, profiles: List[Dict[str, str]]) -> None:
50 """
51 this function looks at the contents of /etc/sysctl.d/ for profiles we have written
52 that should now be removed. It assumes any file with "-cephadm-tuned-profile.conf" in
53 it is written by us any without that are not. Only files written by us are considered
54 candidates for removal. The "profiles" parameter is a list of dictionaries that map
55 profile names to the file contents to actually be written to the
56 /etc/sysctl.d/<profile-name>-cephadm-tuned-profile.conf. For example
57 [
58 {
59 'profile1': 'setting1: value1\nsetting2: value2'
60 },
61 {
62 'profile2': 'setting3: value3'
63 }
64 ]
65 what we want to end up doing is going through the keys of the dicts and appending
66 -cephadm-tuned-profile.conf to the profile names to build our list of profile files that
67 SHOULD be on the host. Then if we see any file names that don't match this, but
68 DO include "-cephadm-tuned-profile.conf" (implying they're from us), remove them.
69 """
70 if host in self.mgr.offline_hosts:
71 return
72 cmd = ['ls', SYSCTL_DIR]
73 found_files = self.mgr.ssh.check_execute_command(host, cmd, log_command=self.mgr.log_refresh_metadata).split('\n')
74 found_files = [s.strip() for s in found_files]
75 profile_names: List[str] = sum([[*p] for p in profiles], []) # extract all profiles names
76 profile_names = list(set(profile_names)) # remove duplicates
77 expected_files = [p + '-cephadm-tuned-profile.conf' for p in profile_names]
78 updated = False
79 for file in found_files:
80 if '-cephadm-tuned-profile.conf' not in file:
81 continue
82 if file not in expected_files:
83 logger.info(f'Removing stray tuned profile file {file}')
84 cmd = ['rm', '-f', f'{SYSCTL_DIR}/{file}']
85 self.mgr.ssh.check_execute_command(host, cmd)
86 updated = True
87 if updated:
88 self.mgr.ssh.check_execute_command(host, ['sysctl', '--system'])
89
90 def _write_tuned_profiles(self, host: str, profiles: List[Dict[str, str]]) -> None:
91 if host in self.mgr.offline_hosts:
92 return
93 updated = False
94 for p in profiles:
95 for profile_name, content in p.items():
96 if self.mgr.cache.host_needs_tuned_profile_update(host, profile_name):
97 logger.info(f'Writing tuned profile {profile_name} to host {host}')
98 profile_filename: str = f'{SYSCTL_DIR}/{profile_name}-cephadm-tuned-profile.conf'
99 self.mgr.ssh.write_remote_file(host, profile_filename, content.encode('utf-8'))
100 updated = True
101 if updated:
102 self.mgr.ssh.check_execute_command(host, ['sysctl', '--system'])
103 self.mgr.cache.last_tuned_profile_update[host] = datetime_now()