-
Notifications
You must be signed in to change notification settings - Fork 78
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Moves inventory policy check for apply into filter
- Loading branch information
Showing
7 changed files
with
251 additions
and
332 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// Copyright 2021 The Kubernetes Authors. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package filter | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
apierrors "k8s.io/apimachinery/pkg/api/errors" | ||
"k8s.io/apimachinery/pkg/api/meta" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | ||
"k8s.io/client-go/dynamic" | ||
"sigs.k8s.io/cli-utils/pkg/inventory" | ||
"sigs.k8s.io/cli-utils/pkg/object" | ||
) | ||
|
||
// InventoryPolicyApplyFilter implements ValidationFilter interface to determine | ||
// if an object should be applied based on the cluster object's inventory id, | ||
// the id for the inventory object, and the inventory policy. | ||
type InventoryPolicyApplyFilter struct { | ||
Client dynamic.Interface | ||
Mapper meta.RESTMapper | ||
Inv inventory.InventoryInfo | ||
InvPolicy inventory.InventoryPolicy | ||
} | ||
|
||
// Name returns a filter identifier for logging. | ||
func (ipaf InventoryPolicyApplyFilter) Name() string { | ||
return "InventoryPolicyApplyFilter" | ||
} | ||
|
||
// Filter returns true if the passed object should be filtered (NOT applied) and | ||
// a filter reason string; false otherwise. Returns an error if one occurred | ||
// during the filter calculation | ||
func (ipaf InventoryPolicyApplyFilter) Filter(obj *unstructured.Unstructured) (bool, string, error) { | ||
if obj == nil { | ||
return true, "missing object", nil | ||
} | ||
// Object must be retrieved from the cluster to get the inventory id. | ||
clusterObj, err := ipaf.getObject(object.UnstructuredToObjMetaOrDie(obj)) | ||
if err != nil { | ||
if apierrors.IsNotFound(err) { | ||
// This simply means the object hasn't been created yet. | ||
return false, "", nil | ||
} | ||
return true, "", err | ||
} | ||
// Check the inventory id "match" and the adopt policy to determine | ||
// if an object should be applied. | ||
canApply, err := inventory.CanApply(ipaf.Inv, clusterObj, ipaf.InvPolicy) | ||
if !canApply { | ||
invMatch := inventory.InventoryIDMatch(ipaf.Inv, clusterObj) | ||
reason := fmt.Sprintf("object removal prevented; inventory match %v : inventory policy: %v", | ||
invMatch, ipaf.InvPolicy) | ||
return true, reason, err | ||
} | ||
return false, "", nil | ||
} | ||
|
||
// getObject retrieves the passed object from the cluster, or an error if one occurred. | ||
func (ipaf InventoryPolicyApplyFilter) getObject(id object.ObjMetadata) (*unstructured.Unstructured, error) { | ||
mapping, err := ipaf.Mapper.RESTMapping(id.GroupKind) | ||
if err != nil { | ||
return nil, err | ||
} | ||
namespacedClient, err := ipaf.Client.Resource(mapping.Resource).Namespace(id.Namespace), nil | ||
if err != nil { | ||
return nil, err | ||
} | ||
return namespacedClient.Get(context.TODO(), id.Name, metav1.GetOptions{}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
// Copyright 2021 The Kubernetes Authors. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package filter | ||
|
||
import ( | ||
"testing" | ||
|
||
"k8s.io/apimachinery/pkg/api/meta/testrestmapper" | ||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | ||
dynamicfake "k8s.io/client-go/dynamic/fake" | ||
"k8s.io/kubectl/pkg/scheme" | ||
"sigs.k8s.io/cli-utils/pkg/common" | ||
"sigs.k8s.io/cli-utils/pkg/inventory" | ||
) | ||
|
||
var invObjTemplate = &unstructured.Unstructured{ | ||
Object: map[string]interface{}{ | ||
"apiVersion": "v1", | ||
"kind": "ConfigMap", | ||
"metadata": map[string]interface{}{ | ||
"name": "inventory-name", | ||
"namespace": "inventory-namespace", | ||
}, | ||
}, | ||
} | ||
|
||
func TestInventoryPolicyApplyFilter(t *testing.T) { | ||
tests := map[string]struct { | ||
inventoryID string | ||
objInventoryID string | ||
policy inventory.InventoryPolicy | ||
filtered bool | ||
isError bool | ||
}{ | ||
"inventory and object ids match, not filtered": { | ||
inventoryID: "foo", | ||
objInventoryID: "foo", | ||
policy: inventory.InventoryPolicyMustMatch, | ||
filtered: false, | ||
isError: false, | ||
}, | ||
"inventory and object ids match and adopt, not filtered": { | ||
inventoryID: "foo", | ||
objInventoryID: "foo", | ||
policy: inventory.AdoptIfNoInventory, | ||
filtered: false, | ||
isError: false, | ||
}, | ||
"inventory and object ids do no match and policy must match, filtered and error": { | ||
inventoryID: "foo", | ||
objInventoryID: "bar", | ||
policy: inventory.InventoryPolicyMustMatch, | ||
filtered: true, | ||
isError: true, | ||
}, | ||
"inventory and object ids do no match and adopt if no inventory, filtered and error": { | ||
inventoryID: "foo", | ||
objInventoryID: "bar", | ||
policy: inventory.AdoptIfNoInventory, | ||
filtered: true, | ||
isError: true, | ||
}, | ||
"inventory and object ids do no match and adopt all, not filtered": { | ||
inventoryID: "foo", | ||
objInventoryID: "bar", | ||
policy: inventory.AdoptAll, | ||
filtered: false, | ||
isError: false, | ||
}, | ||
"object id empty and adopt all, not filtered": { | ||
inventoryID: "foo", | ||
objInventoryID: "", | ||
policy: inventory.AdoptAll, | ||
filtered: false, | ||
isError: false, | ||
}, | ||
"object id empty and policy must match, filtered and error": { | ||
inventoryID: "foo", | ||
objInventoryID: "", | ||
policy: inventory.InventoryPolicyMustMatch, | ||
filtered: true, | ||
isError: true, | ||
}, | ||
} | ||
|
||
for name, tc := range tests { | ||
t.Run(name, func(t *testing.T) { | ||
obj := defaultObj.DeepCopy() | ||
objIDAnnotation := map[string]string{ | ||
"config.k8s.io/owning-inventory": tc.objInventoryID, | ||
} | ||
obj.SetAnnotations(objIDAnnotation) | ||
invIDLabel := map[string]string{ | ||
common.InventoryLabel: tc.inventoryID, | ||
} | ||
invObj := invObjTemplate.DeepCopy() | ||
invObj.SetLabels(invIDLabel) | ||
filter := InventoryPolicyApplyFilter{ | ||
Client: dynamicfake.NewSimpleDynamicClient(scheme.Scheme, obj), | ||
Mapper: testrestmapper.TestOnlyStaticRESTMapper(scheme.Scheme, | ||
scheme.Scheme.PrioritizedVersionsAllGroups()...), | ||
Inv: inventory.WrapInventoryInfoObj(invObj), | ||
InvPolicy: tc.policy, | ||
} | ||
actual, reason, err := filter.Filter(obj) | ||
if tc.isError != (err != nil) { | ||
t.Fatalf("Expected InventoryPolicyFilter error (%v), got (%v)", tc.isError, (err != nil)) | ||
} | ||
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) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.