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
8 from cephadm
.module
import CephadmOrchestrator
10 logger
= logging
.getLogger(__name__
)
12 SYSCTL_DIR
= '/etc/sysctl.d'
15 class TunedProfileUtils():
16 def __init__(self
, mgr
: "CephadmOrchestrator") -> None:
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'
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
] = []
30 for profile
in self
.mgr
.tuned_profiles
.list_profiles():
31 p_str
= self
._profile
_to
_str
(profile
)
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(),
39 networks
=self
.mgr
.cache
.networks
,
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
})
45 for host
, profiles
in host_profile_mapping
.items():
46 self
._remove
_stray
_tuned
_profiles
(host
, profiles
)
47 self
._write
_tuned
_profiles
(host
, profiles
)
49 def _remove_stray_tuned_profiles(self
, host
: str, profiles
: List
[Dict
[str, str]]) -> None:
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
59 'profile1': 'setting1: value1\nsetting2: value2'
62 'profile2': 'setting3: value3'
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.
70 if self
.mgr
.cache
.is_host_unreachable(host
):
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
]
79 for file in found_files
:
80 if '-cephadm-tuned-profile.conf' not in file:
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
)
88 self
.mgr
.ssh
.check_execute_command(host
, ['sysctl', '--system'])
90 def _write_tuned_profiles(self
, host
: str, profiles
: List
[Dict
[str, str]]) -> None:
91 if self
.mgr
.cache
.is_host_unreachable(host
):
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'))
102 self
.mgr
.ssh
.check_execute_command(host
, ['sysctl', '--system'])
103 self
.mgr
.cache
.last_tuned_profile_update
[host
] = datetime_now()