From 25ee7bc1096400f1cb88712b3ab1113900e84d44 Mon Sep 17 00:00:00 2001 From: Jiri Mencak Date: Mon, 11 Apr 2022 22:39:12 +0200 Subject: [PATCH] Remove TuneD profiles no longer used TuneD profiles are extracted into all operands on every Tuned CR change. After their deletion in the CR, they were not removed from the operand's filesystems. In the past, it was not necessary to remove these profiles. This changed with the introduction of conditional profile loading into TuneD. As NTO's Cloud-specific profiles rely on conditional profile loading, this change makes sure all TuneD profiles the current recommended profile depends on are removed from /etc/tuned// once the same TuneD is no longer defined in any of Tuned CRs. Resolves rhbz#2074062. --- pkg/tuned/controller.go | 66 +++++++++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/pkg/tuned/controller.go b/pkg/tuned/controller.go index 16d8598fd4..1ad4282dcf 100644 --- a/pkg/tuned/controller.go +++ b/pkg/tuned/controller.go @@ -272,7 +272,7 @@ func (c *Controller) sync(key wqKey) error { return fmt.Errorf("failed to get Tuned %s: %v", key.name, err) } - change, err := profilesExtract(tuned.Spec.Profile) + change, err := profilesSync(tuned.Spec.Profile) if err != nil { return err } @@ -366,9 +366,13 @@ func profilesEqual(profileFile string, profileData string) bool { } // profilesExtract extracts TuneD daemon profiles to the daemon configuration directory. -// If the data in the to-be-extracted recommended profile or the profiles being included -// from the current recommended profile have changed, the function returns true. -func profilesExtract(profiles []tunedv1.TunedProfile) (bool, error) { +// Returns: +// - True if the data in the to-be-extracted recommended profile or the profiles being +// included from the current recommended profile have changed. +// - A map with successfully extracted TuneD profile names. +// - A map with names of TuneD profiles the current TuneD recommended profile depends on. +// - Error if any or nil. +func profilesExtract(profiles []tunedv1.TunedProfile) (bool, map[string]bool, map[string]bool, error) { var ( change bool ) @@ -376,8 +380,15 @@ func profilesExtract(profiles []tunedv1.TunedProfile) (bool, error) { recommendedProfile, err := getRecommendedProfile() if err != nil { - return change, err + return change, map[string]bool{}, map[string]bool{}, err } + + // Get a list of TuneD profiles names the recommended profile depends on. + recommendedProfileDeps := profileDepends(recommendedProfile) + // Add the recommended profile itself. + recommendedProfileDeps[recommendedProfile] = true + extracted := map[string]bool{} // TuneD profile names present in TuneD CR and successfully extracted to /etc/tuned// + for index, profile := range profiles { if profile.Name == nil { klog.Warningf("profilesExtract(): profile name missing for Profile %v", index) @@ -391,13 +402,9 @@ func profilesExtract(profiles []tunedv1.TunedProfile) (bool, error) { profileFile := fmt.Sprintf("%s/%s", profileDir, tunedConfFile) if err := mkdir(profileDir); err != nil { - return change, fmt.Errorf("failed to create TuneD profile directory %q: %v", profileDir, err) + return change, extracted, recommendedProfileDeps, fmt.Errorf("failed to create TuneD profile directory %q: %v", profileDir, err) } - // Get a list of TuneD profiles names the recommended profile depends on. - recommendedProfileDeps := profileDepends(recommendedProfile) - // Add the recommended profile itself. - recommendedProfileDeps[recommendedProfile] = true if recommendedProfileDeps[*profile.Name] { // Recommended profile (dependency) name matches profile name of the profile // currently being extracted, compare their content. @@ -411,11 +418,46 @@ func profilesExtract(profiles []tunedv1.TunedProfile) (bool, error) { f, err := os.Create(profileFile) if err != nil { - return change, fmt.Errorf("failed to create TuneD profile file %q: %v", profileFile, err) + return change, extracted, recommendedProfileDeps, fmt.Errorf("failed to create TuneD profile file %q: %v", profileFile, err) } defer f.Close() if _, err = f.WriteString(*profile.Data); err != nil { - return change, fmt.Errorf("failed to write TuneD profile file %q: %v", profileFile, err) + return change, extracted, recommendedProfileDeps, fmt.Errorf("failed to write TuneD profile file %q: %v", profileFile, err) + } + extracted[*profile.Name] = true + } + + return change, extracted, recommendedProfileDeps, nil +} + +// profilesSync extracts TuneD daemon profiles to the daemon configuration directory +// and removes any TuneD profiles from /etc/tuned// once the same TuneD +// is no longer defined in the 'profiles' slice. +// Returns: +// - True if the data in the to-be-extracted recommended profile or the profiles being +// included from the current recommended profile have changed. +// - Error if any or nil. +func profilesSync(profiles []tunedv1.TunedProfile) (bool, error) { + change, extractedNew, recommendedProfileDeps, err := profilesExtract(profiles) + if err != nil { + return change, err + } + + // Deal with TuneD profiles absent from Tuned CRs, but still present in /etc/tuned// the recommended profile depends on. + for profile := range recommendedProfileDeps { + if !extractedNew[profile] { + // TuneD profile does not exist in the Tuned CR, but the recommended profile depends on it. + profileDir := fmt.Sprintf("%s/%s", tunedProfilesDirCustom, profile) + if _, err := os.Stat(profileDir); err == nil { + // We have a stale TuneD profile directory in /etc/tuned// + // Remove it. + err := os.RemoveAll(profileDir) + if err != nil { + return change, fmt.Errorf("failed to remove %q: %v", profileDir, err) + } + change = true + klog.Infof("removed TuneD profile %q", profileDir) + } } }