Skip to content

Commit

Permalink
Adds Reason to ValidationFilter and skipped events
Browse files Browse the repository at this point in the history
  • Loading branch information
seans3 committed Jun 26, 2021
1 parent 9b30e8b commit d96d2a0
Show file tree
Hide file tree
Showing 15 changed files with 78 additions and 31 deletions.
8 changes: 6 additions & 2 deletions pkg/apply/event/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,9 @@ type PruneEvent struct {
Identifier object.ObjMetadata
Operation PruneEventOperation
Object *unstructured.Unstructured
Error error
// If prune is skipped, this reason string explains why
Reason string
Error error
}

//go:generate stringer -type=DeleteEventOperation
Expand All @@ -153,5 +155,7 @@ type DeleteEvent struct {
Identifier object.ObjMetadata
Operation DeleteEventOperation
Object *unstructured.Unstructured
Error error
// If delete is skipped, this reason string explains why
Reason string
Error error
}
9 changes: 6 additions & 3 deletions pkg/apply/filter/current-uids-filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
package filter

import (
"fmt"

"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/util/sets"
)
Expand All @@ -24,10 +26,11 @@ func (cuf CurrentUIDFilter) Name() string {
// because the it is a namespace that objects still reside in; otherwise
// returns false. This filter should not be added to the list of filters
// for "destroying", since every object is being deletet. Never returns an error.
func (cuf CurrentUIDFilter) Filter(obj *unstructured.Unstructured) (bool, error) {
func (cuf CurrentUIDFilter) Filter(obj *unstructured.Unstructured) (bool, string, error) {
uid := string(obj.GetUID())
if cuf.CurrentUIDs.Has(uid) {
return true, nil
reason := fmt.Sprintf("object removal prevented; UID just applied: %s", uid)
return true, reason, nil
}
return false, nil
return false, "", nil
}
8 changes: 7 additions & 1 deletion pkg/apply/filter/current-uids-filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,19 @@ func TestCurrentUIDFilter(t *testing.T) {
}
obj := defaultObj.DeepCopy()
obj.SetUID(types.UID(tc.objUID))
actual, err := filter.Filter(obj)
actual, reason, err := filter.Filter(obj)
if err != nil {
t.Fatalf("CurrentUIDFilter unexpected error (%s)", err)
}
if tc.filtered != actual {
t.Errorf("CurrentUIDFilter expected filter (%t), got (%t)", tc.filtered, actual)
}
if tc.filtered && len(reason) == 0 {
t.Errorf("CurrentUIDFilter filtered; expected but missing Reason")
}
if !tc.filtered && len(reason) > 0 {
t.Errorf("CurrentUIDFilter not filtered; received unexpected Reason: %s", reason)
}
})
}
}
6 changes: 4 additions & 2 deletions pkg/apply/filter/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
type ValidationFilter interface {
// Name returns a filter name (usually for logging).
Name() string
// Filter returns true if validation fails or an error.
Filter(obj *unstructured.Unstructured) (bool, error)
// Filter returns true if validation fails. If true a
// reason string is included in the return. If an error happens
// during filtering it is returned.
Filter(obj *unstructured.Unstructured) (bool, string, error)
}
13 changes: 9 additions & 4 deletions pkg/apply/filter/inventory-policy-filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
package filter

import (
"fmt"

"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/cli-utils/pkg/inventory"
)
Expand All @@ -18,17 +20,20 @@ type InventoryPolicyFilter struct {

// Name returns a filter identifier for logging.
func (ipf InventoryPolicyFilter) Name() string {
return "InventoryPolictyFilter"
return "InventoryPolicyFilter"
}

// Filter returns true if the passed object should NOT be pruned (deleted)
// because the "prevent remove" annotation is present; otherwise returns
// false. Never returns an error.
func (ipf InventoryPolicyFilter) Filter(obj *unstructured.Unstructured) (bool, error) {
func (ipf InventoryPolicyFilter) Filter(obj *unstructured.Unstructured) (bool, string, error) {
// Check the inventory id "match" and the adopt policy to determine
// if an object should be pruned (deleted).
if !inventory.CanPrune(ipf.Inv, obj, ipf.InvPolicy) {
return true, nil
invMatch := inventory.InventoryIDMatch(ipf.Inv, obj)
reason := fmt.Sprintf("object removal prevented; inventory match %v : inventory policy: %v",
invMatch, ipf.InvPolicy)
return true, reason, nil
}
return false, nil
return false, "", nil
}
8 changes: 7 additions & 1 deletion pkg/apply/filter/inventory-policy-filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,19 @@ func TestInventoryPolicyFilter(t *testing.T) {
}
obj := defaultObj.DeepCopy()
obj.SetAnnotations(objIDAnnotation)
actual, err := filter.Filter(obj)
actual, reason, err := filter.Filter(obj)
if err != nil {
t.Fatalf("InventoryPolicyFilter unexpected error (%s)", err)
}
if tc.filtered != actual {
t.Errorf("InventoryPolicyFilter expected filter (%t), got (%t)", tc.filtered, actual)
}
if tc.filtered && len(reason) == 0 {
t.Errorf("InventoryPolicyFilter filtered; expected but missing Reason")
}
if !tc.filtered && len(reason) > 0 {
t.Errorf("InventoryPolicyFilter not filtered; received unexpected Reason: %s", reason)
}
})
}
}
9 changes: 6 additions & 3 deletions pkg/apply/filter/local-namespaces-filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
package filter

import (
"fmt"

"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/util/sets"
"sigs.k8s.io/cli-utils/pkg/object"
Expand All @@ -25,11 +27,12 @@ func (lnf LocalNamespacesFilter) Name() string {
// because the it is a namespace that objects still reside in; otherwise
// returns false. This filter should not be added to the list of filters
// for "destroying", since every object is being delete. Never returns an error.
func (lnf LocalNamespacesFilter) Filter(obj *unstructured.Unstructured) (bool, error) {
func (lnf LocalNamespacesFilter) Filter(obj *unstructured.Unstructured) (bool, string, error) {
id := object.UnstructuredToObjMeta(obj)
if id.GroupKind == object.CoreV1Namespace.GroupKind() &&
lnf.LocalNamespaces.Has(id.Name) {
return true, nil
reason := fmt.Sprintf("namespace removal prevented; still in use: %s", id.Name)
return true, reason, nil
}
return false, nil
return false, "", nil
}
8 changes: 7 additions & 1 deletion pkg/apply/filter/local-namespaces-filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,19 @@ func TestLocalNamespacesFilter(t *testing.T) {
}
namespace := testNamespace.DeepCopy()
namespace.SetName(tc.namespace)
actual, err := filter.Filter(namespace)
actual, reason, err := filter.Filter(namespace)
if err != nil {
t.Fatalf("LocalNamespacesFilter unexpected error (%s)", err)
}
if tc.filtered != actual {
t.Errorf("LocalNamespacesFilter expected filter (%t), got (%t)", tc.filtered, actual)
}
if tc.filtered && len(reason) == 0 {
t.Errorf("LocalNamespacesFilter filtered; expected but missing Reason")
}
if !tc.filtered && len(reason) > 0 {
t.Errorf("LocalNamespacesFilter not filtered; received unexpected Reason: %s", reason)
}
})
}
}
9 changes: 6 additions & 3 deletions pkg/apply/filter/prevent-remove-filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
package filter

import (
"fmt"

"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/cli-utils/pkg/common"
)
Expand All @@ -22,11 +24,12 @@ func (prf PreventRemoveFilter) Name() string {
// Filter returns true if the passed object should NOT be pruned (deleted)
// because the "prevent remove" annotation is present; otherwise returns
// false. Never returns an error.
func (prf PreventRemoveFilter) Filter(obj *unstructured.Unstructured) (bool, error) {
func (prf PreventRemoveFilter) Filter(obj *unstructured.Unstructured) (bool, string, error) {
for annotation, value := range obj.GetAnnotations() {
if common.NoDeletion(annotation, value) {
return true, nil
reason := fmt.Sprintf("object removal prevented; delete annotation: %s/%s", annotation, value)
return true, reason, nil
}
}
return false, nil
return false, "", nil
}
8 changes: 7 additions & 1 deletion pkg/apply/filter/prevent-remove-filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,19 @@ func TestPreventDeleteAnnotation(t *testing.T) {
filter := PreventRemoveFilter{}
obj := defaultObj.DeepCopy()
obj.SetAnnotations(tc.annotations)
actual, err := filter.Filter(obj)
actual, reason, err := filter.Filter(obj)
if err != nil {
t.Fatalf("PreventRemoveFilter unexpected error (%s)", err)
}
if tc.expected != actual {
t.Errorf("PreventRemoveFilter expected (%t), got (%t)", tc.expected, actual)
}
if tc.expected && len(reason) == 0 {
t.Errorf("PreventRemoveFilter expected Reason, but none found")
}
if !tc.expected && len(reason) > 0 {
t.Errorf("PreventRemoveFilter expected no Reason, but found (%s)", reason)
}
})
}
}
8 changes: 5 additions & 3 deletions pkg/apply/prune/event-factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
// events for pruning or deleting.
type EventFactory interface {
CreateSuccessEvent(obj *unstructured.Unstructured) event.Event
CreateSkippedEvent(obj *unstructured.Unstructured) event.Event
CreateSkippedEvent(obj *unstructured.Unstructured, reason string) event.Event
CreateFailedEvent(id object.ObjMetadata, err error) event.Event
}

Expand Down Expand Up @@ -42,13 +42,14 @@ func (pef PruneEventFactory) CreateSuccessEvent(obj *unstructured.Unstructured)
}
}

func (pef PruneEventFactory) CreateSkippedEvent(obj *unstructured.Unstructured) event.Event {
func (pef PruneEventFactory) CreateSkippedEvent(obj *unstructured.Unstructured, reason string) event.Event {
return event.Event{
Type: event.PruneType,
PruneEvent: event.PruneEvent{
Operation: event.PruneSkipped,
Object: obj,
Identifier: object.UnstructuredToObjMeta(obj),
Reason: reason,
},
}
}
Expand Down Expand Up @@ -78,13 +79,14 @@ func (def DeleteEventFactory) CreateSuccessEvent(obj *unstructured.Unstructured)
}
}

func (def DeleteEventFactory) CreateSkippedEvent(obj *unstructured.Unstructured) event.Event {
func (def DeleteEventFactory) CreateSkippedEvent(obj *unstructured.Unstructured, reason string) event.Event {
return event.Event{
Type: event.DeleteType,
DeleteEvent: event.DeleteEvent{
Operation: event.DeleteSkipped,
Object: obj,
Identifier: object.UnstructuredToObjMeta(obj),
Reason: reason,
},
}
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/apply/prune/event-factory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func TestEventFactory(t *testing.T) {
t.Errorf("success event expected nil error, got (%s)", err)
}
// Validate the "skipped" event"
actualEvent = eventFactory.CreateSkippedEvent(tc.obj)
actualEvent = eventFactory.CreateSkippedEvent(tc.obj, "fake reason")
if tc.expectedType != actualEvent.Type {
t.Errorf("skipped event expected type (%s), got (%s)",
tc.expectedType, actualEvent.Type)
Expand Down
5 changes: 3 additions & 2 deletions pkg/apply/prune/prune.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,11 @@ func (po *PruneOptions) Prune(pruneObjs []*unstructured.Unstructured,
klog.V(5).Infof("attempting prune: %s", pruneID)
// Check filters to see if we're prevented from pruning/deleting object.
var filtered bool
var reason string
var err error
for _, filter := range pruneFilters {
klog.V(6).Infof("prune filter %s: %s", filter.Name(), pruneID)
filtered, err = filter.Filter(pruneObj)
filtered, reason, err = filter.Filter(pruneObj)
if err != nil {
if klog.V(5).Enabled() {
klog.Errorf("error during %s, (%s): %s", filter.Name(), pruneID, err)
Expand All @@ -111,7 +112,7 @@ func (po *PruneOptions) Prune(pruneObjs []*unstructured.Unstructured,
}
if filtered {
klog.V(4).Infof("prune filtered by %s: %s", filter.Name(), pruneID)
taskContext.EventChannel() <- eventFactory.CreateSkippedEvent(pruneObj)
taskContext.EventChannel() <- eventFactory.CreateSkippedEvent(pruneObj, reason)
taskContext.CapturePruneFailure(pruneID)
break
}
Expand Down
6 changes: 3 additions & 3 deletions pkg/inventory/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ const (
NoMatch
)

func inventoryIDMatch(inv InventoryInfo, obj *unstructured.Unstructured) inventoryIDMatchStatus {
func InventoryIDMatch(inv InventoryInfo, obj *unstructured.Unstructured) inventoryIDMatchStatus {
annotations := obj.GetAnnotations()
value, found := annotations[owningInventoryKey]
if !found {
Expand All @@ -93,7 +93,7 @@ func CanApply(inv InventoryInfo, obj *unstructured.Unstructured, policy Inventor
if obj == nil {
return true, nil
}
matchStatus := inventoryIDMatch(inv, obj)
matchStatus := InventoryIDMatch(inv, obj)
switch matchStatus {
case Empty:
if policy != InventoryPolicyMustMatch {
Expand All @@ -118,7 +118,7 @@ func CanPrune(inv InventoryInfo, obj *unstructured.Unstructured, policy Inventor
if obj == nil {
return false
}
matchStatus := inventoryIDMatch(inv, obj)
matchStatus := InventoryIDMatch(inv, obj)
switch matchStatus {
case Empty:
return policy == AdoptIfNoInventory || policy == AdoptAll
Expand Down
2 changes: 1 addition & 1 deletion pkg/inventory/policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func TestInventoryIDMatch(t *testing.T) {
},
}
for _, tc := range testcases {
actual := inventoryIDMatch(tc.inv, tc.obj)
actual := InventoryIDMatch(tc.inv, tc.obj)
if actual != tc.expected {
t.Errorf("expected %v, but got %v", tc.expected, actual)
}
Expand Down

0 comments on commit d96d2a0

Please sign in to comment.