Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OCPBUGS-28647: deferred updates: cleanups #1119

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ $(GOBINDATA_BIN):

test-e2e: $(BINDATA)
for d in core basic reboots reboots/sno deferred; do \
KUBERNETES_CONFIG="$(KUBECONFIG)" $(GO) test -v -timeout 40m ./test/e2e/$$d -ginkgo.v -ginkgo.no-color -ginkgo.fail-fast || exit; \
KUBERNETES_CONFIG="$(KUBECONFIG)" $(GO) test -v -timeout 40m ./test/e2e/$$d -ginkgo.v -ginkgo.no-color -ginkgo.fail-fast -ginkgo.label-filter=!flaky || exit; \
done

.PHONY: test-e2e-local
Expand Down
2 changes: 1 addition & 1 deletion pkg/tuned/cmd/render/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ func render(inputDir []string, outputDir string, mcpName string) error {
for _, t := range tuneD {
tunedProfiles = append(tunedProfiles, t.Spec.Profile...)
}
_, _, _, _, err = tunedpkg.ProfilesExtract(tunedProfiles, recommendedProfile)
_, err = tunedpkg.ProfilesExtract(tunedProfiles, recommendedProfile)
if err != nil {
klog.Errorf("error extracting tuned profiles : %v", err)
return fmt.Errorf("error extracting tuned profiles: %w", err)
Expand Down
81 changes: 49 additions & 32 deletions pkg/tuned/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ const (
// be generous and give it 10s.
tunedGracefulExitWait = time.Second * time.Duration(10)
ocpTunedHome = "/var/lib/ocp-tuned"
ocpTunedRunDir = "/run/" + programName
ocpTunedRunDir = "/run/ocp-tuned"
ocpTunedProvider = ocpTunedHome + "/provider"
// With the less aggressive rate limiter, retries will happen at 100ms*2^(retry_n-1):
// 100ms, 200ms, 400ms, 800ms, 1.6s, 3.2s, 6.4s, 12.8s, 25.6s, 51.2s, 102.4s, 3.4m, 6.8m, 13.7m, 27.3m
Expand Down Expand Up @@ -389,15 +389,23 @@ func profilesEqual(profileFile string, profileData string) bool {
return profileData == string(content)
}

type ExtractedProfiles struct {
// True if the data in the to-be-extracted recommended profile or the profiles being
// included from the current recommended profile have changed.
Changed bool
// If the data changed, the fingerprint of the new profile, or "" otherwise.
Fingerprint string
// A map with successfully extracted TuneD profile names.
Names map[string]bool
// A map with names of TuneD profiles the current TuneD recommended profile depends on.
Dependencies map[string]bool
}

// ProfilesExtract extracts TuneD daemon profiles to tunedProfilesDirCustom directory.
// Returns:
// - True if the data in the to-be-extracted recommended profile or the profiles being
// included from the current recommended profile have changed.
// - If the data changed, the fingerprint of the new profile, or "" otherwise.
// - A map with successfully extracted TuneD profile names.
// - A map with names of TuneD profiles the current TuneD recommended profile depends on.
// - ExtractedProfiles with the details of the operation performed
// - Error if any or nil.
func ProfilesExtract(profiles []tunedv1.TunedProfile, recommendedProfile string) (bool, string, map[string]bool, map[string]bool, error) {
func ProfilesExtract(profiles []tunedv1.TunedProfile, recommendedProfile string) (ExtractedProfiles, error) {
klog.Infof("profilesExtract(): extracting %d TuneD profiles (recommended=%s)", len(profiles), recommendedProfile)
// Get a list of TuneD profiles names the recommended profile depends on.
deps := profileDepends(recommendedProfile)
Expand All @@ -409,7 +417,7 @@ func ProfilesExtract(profiles []tunedv1.TunedProfile, recommendedProfile string)

// profilesExtractPathWithDeps is like ProfilesExtract but takes explicit profiles root dir path and
// explicit dependencies, so it's easier to test. To be used only internally.
func profilesExtractPathWithDeps(profilesRootDir string, profiles []tunedv1.TunedProfile, recommendedProfile string, recommendedProfileDeps map[string]bool) (bool, string, map[string]bool, map[string]bool, error) {
func profilesExtractPathWithDeps(profilesRootDir string, profiles []tunedv1.TunedProfile, recommendedProfile string, recommendedProfileDeps map[string]bool) (ExtractedProfiles, error) {
var (
change bool = false
extracted map[string]bool = map[string]bool{} // TuneD profile names present in TuneD CR and successfully extracted to tunedProfilesDirCustom
Expand All @@ -428,7 +436,11 @@ func profilesExtractPathWithDeps(profilesRootDir string, profiles []tunedv1.Tune
profileFile := filepath.Join(profileDir, tunedConfFile)

if err := os.MkdirAll(profileDir, os.ModePerm); err != nil {
return change, "", extracted, recommendedProfileDeps, fmt.Errorf("failed to create TuneD profile directory %q: %v", profileDir, err)
return ExtractedProfiles{
Changed: change,
Names: extracted,
Dependencies: recommendedProfileDeps,
}, fmt.Errorf("failed to create TuneD profile directory %q: %v", profileDir, err)
}

if recommendedProfileDeps[*profile.Name] {
Expand All @@ -444,15 +456,24 @@ func profilesExtractPathWithDeps(profilesRootDir string, profiles []tunedv1.Tune

err := os.WriteFile(profileFile, []byte(*profile.Data), 0644)
if err != nil {
return change, "", extracted, recommendedProfileDeps, fmt.Errorf("failed to write TuneD profile file %q: %v", profileFile, err)
return ExtractedProfiles{
Changed: change,
Names: extracted,
Dependencies: recommendedProfileDeps,
}, fmt.Errorf("failed to write TuneD profile file %q: %v", profileFile, err)
}
extracted[*profile.Name] = true
klog.V(2).Infof("profilesExtract(): extracted profile %q to %q (%d bytes)", *profile.Name, profileFile, len(*profile.Data))
}

profilesFP := profilesFingerprint(profiles, recommendedProfile)
klog.Infof("profilesExtract(): fingerprint of extracted profiles: %q", profilesFP)
return change, profilesFP, extracted, recommendedProfileDeps, nil
return ExtractedProfiles{
Changed: change,
Fingerprint: profilesFP,
Names: extracted,
Dependencies: recommendedProfileDeps,
}, nil
}

// profilesRepackPath reconstructs the TunedProfile object from the data unpacked on the node
Expand Down Expand Up @@ -506,16 +527,17 @@ func profilesRepackPath(recommendFilePath, profilesRootDir string) ([]tunedv1.Tu
// - The synced profile fingerprint.
// - Error if any or nil.
func profilesSync(profiles []tunedv1.TunedProfile, recommendedProfile string) (bool, string, error) {
change, profilesFP, extractedNew, recommendedProfileDeps, err := ProfilesExtract(profiles, recommendedProfile)
extracted, err := ProfilesExtract(profiles, recommendedProfile)
if err != nil {
return change, "", err
return extracted.Changed, "", err
}

dirEntries, err := os.ReadDir(tunedProfilesDirCustom)
if err != nil {
return change, "", err
return extracted.Changed, "", err
}

changed := extracted.Changed // shortcut, but we also modify before
// Deal with TuneD profiles absent from Tuned CRs, but still present in <tunedProfilesDirCustom>/<profile>/
for _, dirEntry := range dirEntries {
profile := dirEntry.Name()
Expand All @@ -529,26 +551,26 @@ func profilesSync(profiles []tunedv1.TunedProfile, recommendedProfile string) (b
continue
}

if extractedNew[profile] {
if extracted.Names[profile] {
// Do not delete the freshly extracted profiles. These are the profiles present in the Profile CR.
continue
}
// This TuneD profile does not exist in the Profile CR, delete it.
profileDir := fmt.Sprintf("%s/%s", tunedProfilesDirCustom, profile)
err := os.RemoveAll(profileDir)
if err != nil {
return change, "", fmt.Errorf("failed to remove %q: %v", profileDir, err)
return changed, "", fmt.Errorf("failed to remove %q: %v", profileDir, err)
}
klog.Infof("profilesSync(): removed TuneD profile %q", profileDir)

if recommendedProfileDeps[profile] {
if extracted.Dependencies[profile] {
// This TuneD profile does not exist in the Profile CR, but the recommended profile depends on it.
// Trigger a change to report a configuration issue -- we depend on a profile that does not exist.
change = true
changed = true
}
}

return change, profilesFP, nil
return changed, extracted.Fingerprint, nil
}

// filterAndSortProfiles returns a slice of valid (non-nil name, non-nil data) profiles
Expand Down Expand Up @@ -1040,16 +1062,14 @@ func (c *Controller) changeSyncerTuneD(change Change) (synced bool, err error) {
}

// Does the current TuneD process have the reapply_sysctl option turned on?
reapplySysctl := c.tunedMainCfg.Section("").Key("reapply_sysctl").MustBool()
if reapplySysctl != change.reapplySysctl {
if reapplySysctl := c.tunedMainCfg.Section("").Key("reapply_sysctl").MustBool(); reapplySysctl != change.reapplySysctl {
klog.V(4).Infof("reapplySysctl rewriting configuration file")

if err = iniCfgSetKey(c.tunedMainCfg, "reapply_sysctl", !reapplySysctl); err != nil {
return false, err
}
err = iniFileSave(tunedMainConfPath, c.tunedMainCfg)
if err != nil {
return false, fmt.Errorf("failed to write global TuneD configuration file: %v", err)
return false, fmt.Errorf("failed to write global TuneD configuration file: %w", err)
}
klog.V(4).Infof("reapplySysctl triggering tuned restart")
restart = true // A complete restart of the TuneD daemon is needed due to configuration change in tuned-main.conf file.
Expand Down Expand Up @@ -1384,30 +1404,27 @@ func (c *Controller) storeDeferredUpdate(deferredFP string) (derr error) {
// If the file is absent, a node restart is assumed and true is returned.
// - Error if any.
func (c *Controller) recoverAndClearDeferredUpdate() (string, bool, error) {
isReboot := false

deferredFP, err := os.ReadFile(tunedDeferredUpdatePersistentFilePath)
if err != nil {
if os.IsNotExist(err) {
klog.Infof("recover: no pending deferred change")
return "", isReboot, nil
return "", false, nil
}
klog.Infof("recover: failed to restore pending deferred change: %v", err)
return "", isReboot, err
return "", false, err
}
pendingFP := strings.TrimSpace(string(deferredFP))
err = os.Remove(tunedDeferredUpdatePersistentFilePath)
klog.Infof("recover: found pending deferred update: %q", pendingFP)

if _, errEph := os.Stat(tunedDeferredUpdateEphemeralFilePath); errEph != nil {
if os.IsNotExist(errEph) {
isReboot = true
} else {
klog.Infof("recover: failed to detect node restart, assuming not: %v", err)
return "", false, errEph
return pendingFP, true, err
}
klog.Infof("recover: failed to detect node restart, assuming not: %v", err)
return "", false, errEph
}
return pendingFP, isReboot, err
return pendingFP, false, err
}

func (c *Controller) informerEventHandler(workqueueKey wqKeyKube) cache.ResourceEventHandlerFuncs {
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/deferred/basic.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
"github.com/openshift/cluster-node-tuning-operator/test/e2e/util"
)

var _ = ginkgo.Describe("[deferred][profile_status] Profile deferred", func() {
var _ = ginkgo.Describe("[deferred][profile-status] Profile deferred", ginkgo.Label("deferred", "profile-status"), func() {
ginkgo.Context("when applied", func() {
var (
createdTuneds []string
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/deferred/non_regression.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
"github.com/openshift/cluster-node-tuning-operator/test/e2e/util"
)

var _ = ginkgo.Describe("[deferred][non_regression] Profile non-deferred", func() {
var _ = ginkgo.Describe("[deferred][non-regression] Profile non-deferred", ginkgo.Label("deferred", "non-regression"), func() {
ginkgo.Context("when applied", func() {
var (
createdTuneds []string
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/deferred/restart.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
"github.com/openshift/cluster-node-tuning-operator/test/e2e/util/wait"
)

var _ = ginkgo.Describe("[deferred][restart] Profile deferred", func() {
var _ = ginkgo.Describe("[deferred][restart][slow][disruptive][flaky] Profile deferred", ginkgo.Label("deferred", "restart", "slow", "disruptive", "flaky"), func() {
ginkgo.Context("when restarting", func() {
var (
createdTuneds []string
Expand Down