Skip to content

Commit

Permalink
Add warnings field to TailoredProfile CRD
Browse files Browse the repository at this point in the history
  • Loading branch information
Vincent056 committed Nov 17, 2023
1 parent a0800db commit 34617c6
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ spec:
state:
description: The current state of the tailored profile
type: string
warnings:
type: string
type: object
type: object
served: true
Expand Down
14 changes: 6 additions & 8 deletions pkg/apis/compliance/v1alpha1/tailoredprofile_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,16 @@ import (
// FIXME: move name/rationale to a common struct with an interface?

// DisableOutdatedReferenceValidation a label is used to disable validation of outdated references
const DisableOutdatedReferenceValidation = "compliance.openshift.io/outdated-reference-validation-disable"
const DisableOutdatedReferenceValidation = "compliance.openshift.io/disable-outdated-reference-validation"

// PurneOutdatedReferencesAnnotationKey is the annotation key used to indicate that the outdated references of rules or variables should be pruned
const PurneOutdatedReferencesAnnotationKey = "compliance.openshift.io/prune-outdated-references"
// PruneOutdatedReferencesAnnotationKey is the annotation key used to indicate that the outdated references of rules or variables should be pruned
const PruneOutdatedReferencesAnnotationKey = "compliance.openshift.io/prune-outdated-references"

// RuleLastCheckTypeChangedAnnotationKey is the annotation key used to indicate that the rule check type has changed, store its previous check type
const RuleLastCheckTypeChangedAnnotationKey = "compliance.openshift.io/rule-last-check-type"

// VariableDeprecatedAnnotationKey is the annotation key used to indicate that the variable is deprecated
const VariableDeprecatedAnnotationKey = "compliance.openshift.io/variable-deprecated"

// DeprecatedRuleAnnotationKey is the annotation key used to indicate that the rule is deprecated
const DeprecatedRuleAnnotationKey = "compliance.openshift.io/deprecated-rule"
// DeprecatedAnnotationKey is the annotation key used to indicate that the variable or rule is deprecated
const DeprecatedAnnotationKey = "compliance.openshift.io/deprecated"

// RuleReferenceSpec specifies a rule to be selected/deselected, as well as the reason why
type RuleReferenceSpec struct {
Expand Down Expand Up @@ -89,6 +86,7 @@ type TailoredProfileStatus struct {
// The current state of the tailored profile
State TailoredProfileState `json:"state,omitempty"`
ErrorMessage string `json:"errorMessage,omitempty"`
Warnings string `json:"warnings,omitempty"`
}

// OutputRef is a reference to the object created from the tailored profile
Expand Down
12 changes: 8 additions & 4 deletions pkg/controller/profilebundle/profilebundle_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -580,14 +580,18 @@ func workloadNeedsUpdate(image string, depl *appsv1.Deployment) bool {
return true
}

isSameContentImage := false
isSaneProfileparserImage := false

for _, container := range initContainers {
if container.Name == "content-container" {
// we need an update if the image reference doesn't match.
return image != container.Image
isSameContentImage = container.Image == image
}
if container.Name == "profileparser" {
isSaneProfileparserImage = utils.GetComponentImage(utils.OPERATOR) == container.Image
}
}

// If we didn't find the container we were looking for. There's something funky going on
// and we should try to update anyway
return true
return !(isSameContentImage && isSaneProfileparserImage)
}
102 changes: 73 additions & 29 deletions pkg/controller/tailoredprofile/tailoredprofile_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,26 +208,37 @@ func (r *ReconcileTailoredProfile) Reconcile(ctx context.Context, request reconc
if _, ok := ann[cmpv1alpha1.DisableOutdatedReferenceValidation]; ok {
reqLogger.Info("Reference validation is disabled, skipping validation")
} else if isValidationRequired(instance) {
pureOutdated := false
if _, ok := ann[cmpv1alpha1.PurneOutdatedReferencesAnnotationKey]; ok {
pureOutdated = true
reqLogger.Info("Validating TailoredProfile")
pruneOutdated := false
if _, ok := ann[cmpv1alpha1.PruneOutdatedReferencesAnnotationKey]; ok {
pruneOutdated = true
}
// remove any deprecated variables or rules from the tailored profile
doContinue, err := r.handleDeprecation(instance, reqLogger, pureOutdated)
doContinue, variableNeedtoBeDeprecatedList, ruleNeedToBeDeprecatedList, err := r.handleDeprecation(instance, reqLogger, pruneOutdated)
if err != nil {
return reconcile.Result{}, err
}
if !doContinue {
return reconcile.Result{}, nil
}

doContinue, err = r.handleMigration(instance, reqLogger, pureOutdated)
doContinue, ruleNeedToBeMigratedList, err := r.handleRulePruning(instance, reqLogger, pruneOutdated)
if err != nil {
return reconcile.Result{}, err
}
if !doContinue {
return reconcile.Result{}, nil
}

warningMsg := generateWarningMessage(variableNeedtoBeDeprecatedList, ruleNeedToBeDeprecatedList, ruleNeedToBeMigratedList)
// check if warning message matches the previous warning message
// if it does, we don't need to update the tp, if not we need to update it with the new warning message
if warningMsg != instance.Status.Warnings {
tpCopy := instance.DeepCopy()
tpCopy.Status.Warnings = warningMsg
r.Client.Status().Update(context.TODO(), tpCopy)
}

}

rules, ruleErr := r.getRulesFromSelections(instance, pb)
Expand Down Expand Up @@ -265,24 +276,49 @@ func (r *ReconcileTailoredProfile) Reconcile(ctx context.Context, request reconc
return r.ensureOutputObject(instance, tpcm, reqLogger)
}

// handleMigration check if there are any migrated rules in the TailoredProfile
// and we will handle the migration of the tailored profile accordingly
func (r *ReconcileTailoredProfile) handleMigration(
v1alphaTp *cmpv1alpha1.TailoredProfile, logger logr.Logger, pruneOudated bool) (bool, error) {
// generateWarningMessage generates a warning message for the user
// based on the list of deprecated variables and rules that are detected
// as well as the list of migrated rules that are detected that are not
// migrated yet
func generateWarningMessage(variableNeedtoBeDeprecatedList []string, ruleNeedToBeDeprecatedList []string, ruleNeedToBeMigratedList []string) string {
var warningMessage string
if len(variableNeedtoBeDeprecatedList) > 0 {
warningMessage = fmt.Sprintf("The following variables are deprecated and need to be removed from the TailoredProfile: %s\n", strings.Join(variableNeedtoBeDeprecatedList, ","))
}
if len(ruleNeedToBeDeprecatedList) > 0 {
if warningMessage != "" {
warningMessage = fmt.Sprintf("%sThe following rules are deprecated and need to be removed from the TailoredProfile: %s\n", warningMessage, strings.Join(ruleNeedToBeDeprecatedList, ","))
} else {
warningMessage = fmt.Sprintf("The following rules are deprecated and need to be removed from the TailoredProfile: %s\n", strings.Join(ruleNeedToBeDeprecatedList, ","))
}
}
if len(ruleNeedToBeMigratedList) > 0 {
if warningMessage != "" {
warningMessage = fmt.Sprintf("%sThe following rules are migrated and need to be migrated or removed from the TailoredProfile: %s\n", warningMessage, strings.Join(ruleNeedToBeMigratedList, ","))
} else {
warningMessage = fmt.Sprintf("The following rules are migrated and need to be migrated or removed from the TailoredProfile: %s\n", strings.Join(ruleNeedToBeMigratedList, ","))
}
}
return warningMessage
}

// handleRulePruning check if there are any migrated rules in the TailoredProfile
// and we will handle the migration of the tailored profile accordingly
func (r *ReconcileTailoredProfile) handleRulePruning(
v1alphaTp *cmpv1alpha1.TailoredProfile, logger logr.Logger, pruneOudated bool) (doContinue bool, ruleNeedToBeMigratedList []string, err error) {
doContinue = true
// Get the list of KubeletConfig rules that are migrated with checkType change
migratedRules, err := r.getMigratedRules(v1alphaTp, logger)
if err != nil {
return false, err
return false, nil, err
}

if len(migratedRules) == 0 {
return true, nil
return true, nil, nil
}

profileType := utils.GetScanType(v1alphaTp.GetAnnotations())

doContinue := true
v1alphaTpCP := v1alphaTp.DeepCopy()

// check if there are any disabled rules that are migrated
Expand All @@ -295,10 +331,11 @@ func (r *ReconcileTailoredProfile) handleMigration(
if pruneOudated {
doContinue = false
logger.Info("Removing migrated rule from disableRules", "rule", rule.Name)
r.Eventf(v1alphaTp, corev1.EventTypeWarning, "TailoredProfileMigratedRule", "Removing migrated rule: %s from disableRules", rule.Name)
r.Eventf(v1alphaTp, corev1.EventTypeWarning, "TailoredProfileMigratedRule", "Removing migrated rule: %s from disableRules, it has been changed from %s to %s", rule.Name, checkType, profileType)
} else {
logger.Info("Migrated rule detected in disableRules", "rule", rule.Name)
r.Eventf(v1alphaTp, corev1.EventTypeWarning, "TailoredProfileMigratedRule", "Migrated rule detected: %s Please migrate it or remove it from the TailoredProfile", rule.Name)
r.Eventf(v1alphaTp, corev1.EventTypeWarning, "TailoredProfileMigratedRule", "%s type changed from %s to %s. Please migrate it or remove it from the TailoredProfile", rule.Name, checkType, profileType)
ruleNeedToBeMigratedList = append(ruleNeedToBeMigratedList, rule.Name)
newRules = append(newRules, *rule)
}
continue
Expand All @@ -319,10 +356,11 @@ func (r *ReconcileTailoredProfile) handleMigration(
if pruneOudated {
doContinue = false
logger.Info("Removing migrated rule from enableRules", "rule", rule.Name)
r.Eventf(v1alphaTp, corev1.EventTypeWarning, "TailoredProfileMigratedRule", "Removing migrated rule %s from enableRules", rule.Name)
r.Eventf(v1alphaTp, corev1.EventTypeWarning, "TailoredProfileMigratedRule", "Removing migrated rule %s from enableRules, it has been changed from %s to %s", rule.Name, checkType, profileType)
} else {
logger.Info("Migrated rule detected in enableRules", "rule", rule.Name)
r.Eventf(v1alphaTp, corev1.EventTypeWarning, "TailoredProfileMigratedRule", "Migrated rule detected: %s Please migrate it or remove it from the TailoredProfile", rule.Name)
r.Eventf(v1alphaTp, corev1.EventTypeWarning, "TailoredProfileMigratedRule", "%s type changed from %s to %s. Please migrate it or remove it from the TailoredProfile", rule.Name, checkType, profileType)
ruleNeedToBeMigratedList = append(ruleNeedToBeMigratedList, rule.Name)
newRules = append(newRules, *rule)
}
continue
Expand All @@ -346,35 +384,34 @@ func (r *ReconcileTailoredProfile) handleMigration(

if !doContinue {
err = r.Client.Update(context.TODO(), v1alphaTpCP)
logger.Info("Updating TailoredProfile with migrated rules removed")
logger.Info("Updating TailoredProfile after handling migration")
if err != nil {
return false, err
return false, nil, err
}
}
return doContinue, nil
return doContinue, ruleNeedToBeMigratedList, nil
}

func isValidationRequired(tp *cmpv1alpha1.TailoredProfile) bool {
if tp.Spec.Extends != "" {
return tp.Spec.DisableRules != nil || tp.Spec.EnableRules != nil || tp.Spec.ManualRules != nil || tp.Spec.SetValues != nil
}
return tp.Spec.EnableRules != nil || tp.Spec.ManualRules != nil
return tp.Spec.EnableRules != nil || tp.Spec.ManualRules != nil || tp.Spec.SetValues != nil
}

func (r *ReconcileTailoredProfile) handleDeprecation(
v1alphaTp *cmpv1alpha1.TailoredProfile, logger logr.Logger, pruneOudated bool) (bool, error) {

v1alphaTp *cmpv1alpha1.TailoredProfile, logger logr.Logger, pruneOudated bool) (doContinue bool, variableNeedtoBeDeprecatedList []string, ruleNeedToBeDeprecatedList []string, err error) {
doContinue = true
deprecatedRules, err := r.getDeprecatedRules(v1alphaTp, logger)
if err != nil {
return false, err
return false, nil, nil, err
}

deprecatedVariables, err := r.getDeprecatedVariables(v1alphaTp, logger)
if err != nil {
return false, err
return false, nil, nil, err
}

doContinue := true
v1alphaTpCP := v1alphaTp.DeepCopy()

// remove any deprecated variables from the tailored profile
Expand All @@ -390,6 +427,7 @@ func (r *ReconcileTailoredProfile) handleDeprecation(
} else {
logger.Info("Deprecated variable detected", "variable", variables.Name)
r.Eventf(v1alphaTp, corev1.EventTypeWarning, "TailoredProfileDeprecatedSetting", "Deprecated variable detected: %s Please remove it from the TailoredProfile", variables.Name)
variableNeedtoBeDeprecatedList = append(variableNeedtoBeDeprecatedList, variables.Name)
newVariables = append(newVariables, *variables)
}
continue
Expand All @@ -415,6 +453,7 @@ func (r *ReconcileTailoredProfile) handleDeprecation(
} else {
logger.Info("Deprecated rule detected in enableRules", "rule", rule.Name)
r.Eventf(v1alphaTp, corev1.EventTypeWarning, "TailoredProfileDeprecatedSetting", "Deprecated rule detected: %s Please remove it from the TailoredProfile", rule.Name)
ruleNeedToBeDeprecatedList = append(ruleNeedToBeDeprecatedList, rule.Name)
newRules = append(newRules, *rule)
}
continue
Expand All @@ -439,6 +478,7 @@ func (r *ReconcileTailoredProfile) handleDeprecation(
} else {
logger.Info("Deprecated rule detected in disableRules", "rule", rule.Name)
r.Eventf(v1alphaTp, corev1.EventTypeWarning, "TailoredProfileDeprecatedSetting", "Deprecated rule detected: %s Please remove it from the TailoredProfile", rule.Name)
ruleNeedToBeDeprecatedList = append(ruleNeedToBeDeprecatedList, rule.Name)
newRules = append(newRules, *rule)
}
continue
Expand Down Expand Up @@ -466,10 +506,10 @@ func (r *ReconcileTailoredProfile) handleDeprecation(
err = r.Client.Update(context.TODO(), v1alphaTpCP)
logger.Info("Updating TailoredProfile with deprecated rules and variables removed")
if err != nil {
return false, err
return false, nil, nil, err
}
}
return doContinue, nil
return doContinue, variableNeedtoBeDeprecatedList, ruleNeedToBeDeprecatedList, nil
}

// getMigratedRules get list of rules and check if it has RuleLastCheckTypeChangedAnnotationKey annotation
Expand Down Expand Up @@ -518,7 +558,7 @@ func (r *ReconcileTailoredProfile) getDeprecatedVariables(tp *cmpv1alpha1.Tailor
for vi := range variableList.Items {
variable := &variableList.Items[vi]
if variable.Annotations != nil {
if _, ok := variable.Annotations[cmpv1alpha1.VariableDeprecatedAnnotationKey]; ok {
if _, ok := variable.Annotations[cmpv1alpha1.DeprecatedAnnotationKey]; ok {
deprecatedVariables[variable.GetName()] = ""
}
}
Expand All @@ -542,7 +582,7 @@ func (r *ReconcileTailoredProfile) getDeprecatedRules(tp *cmpv1alpha1.TailoredPr
for ri := range ruleList.Items {
rule := &ruleList.Items[ri]
if rule.Annotations != nil {
if _, ok := rule.Annotations[cmpv1alpha1.DeprecatedRuleAnnotationKey]; ok {
if _, ok := rule.Annotations[cmpv1alpha1.DeprecatedAnnotationKey]; ok {
deprecatedRules[rule.GetName()] = ""
}
}
Expand Down Expand Up @@ -858,6 +898,10 @@ func assertValidRuleTypes(rules map[string]*cmpv1alpha1.Rule) error {
if rule.CheckType == cmpv1alpha1.CheckTypeNone {
continue
}
// check if the rule is a migrated rule and if it is, we should not check the type
if _, ok := rule.Annotations[cmpv1alpha1.RuleLastCheckTypeChangedAnnotationKey]; ok {
continue
}
// Initialize expected check type
if expectedCheckType == "" {
expectedCheckType = rule.CheckType
Expand Down
Loading

0 comments on commit 34617c6

Please sign in to comment.