1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-28 02:18:15 +00:00

fix: refactor cli values loading and remove dead code (#7739)

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
Charles-Edouard Brétéché 2023-07-03 15:22:05 +02:00 committed by GitHub
parent 4560df0dc5
commit 26e5bd76c7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 163 additions and 171 deletions

View file

@ -32,20 +32,6 @@ import (
yaml1 "sigs.k8s.io/yaml"
)
type Resource struct {
Name string `json:"name"`
Values map[string]string `json:"values"`
}
type Policy struct {
Name string `json:"name"`
Resources []Resource `json:"resources"`
}
type Values struct {
Policies []Policy `json:"policies"`
}
type SkippedInvalidPolicies struct {
skipped []string
invalid []string
@ -73,7 +59,6 @@ type ApplyCommandConfig struct {
var (
applyHelp = `
To apply on a resource:
kyverno apply /path/to/policy.yaml /path/to/folderOfPolicies --resource=/path/to/resource1 --resource=/path/to/resource2
@ -84,58 +69,58 @@ To apply on a cluster:
kyverno apply /path/to/policy.yaml /path/to/folderOfPolicies --cluster
To apply policies from a gitSourceURL on a cluster:
Example: Taking github.com as a gitSourceURL here. Some other standards gitSourceURL are: gitlab.com , bitbucket.org , etc.
kyverno apply https://github.com/kyverno/policies/openshift/ --git-branch main --cluster
Example: Taking github.com as a gitSourceURL here. Some other standards gitSourceURL are: gitlab.com , bitbucket.org , etc.
kyverno apply https://github.com/kyverno/policies/openshift/ --git-branch main --cluster
To apply policy with variables:
1. To apply single policy with variable on single resource use flag "set".
Example:
kyverno apply /path/to/policy.yaml --resource /path/to/resource.yaml --set <variable1>=<value1>,<variable2>=<value2>
1. To apply single policy with variable on single resource use flag "set".
Example:
kyverno apply /path/to/policy.yaml --resource /path/to/resource.yaml --set <variable1>=<value1>,<variable2>=<value2>
2. To apply multiple policy with variable on multiple resource use flag "values_file".
Example:
kyverno apply /path/to/policy1.yaml /path/to/policy2.yaml --resource /path/to/resource1.yaml --resource /path/to/resource2.yaml -f /path/to/value.yaml
2. To apply multiple policy with variable on multiple resource use flag "values_file".
Example:
kyverno apply /path/to/policy1.yaml /path/to/policy2.yaml --resource /path/to/resource1.yaml --resource /path/to/resource2.yaml -f /path/to/value.yaml
Format of value.yaml:
Format of value.yaml:
policies:
- name: <policy1 name>
rules:
- name: <rule1 name>
values:
<context variable1 in policy1 rule1>: <value>
<context variable2 in policy1 rule1>: <value>
- name: <rule2 name>
values:
<context variable1 in policy1 rule2>: <value>
<context variable2 in policy1 rule2>: <value>
resources:
- name: <resource1 name>
values:
<variable1 in policy1>: <value>
<variable2 in policy1>: <value>
- name: <resource2 name>
values:
<variable1 in policy1>: <value>
<variable2 in policy1>: <value>
- name: <policy2 name>
resources:
- name: <resource1 name>
values:
<variable1 in policy2>: <value>
<variable2 in policy2>: <value>
- name: <resource2 name>
values:
<variable1 in policy2>: <value>
<variable2 in policy2>: <value>
namespaceSelector:
- name: <namespace1 name>
labels:
<label key>: <label value>
- name: <namespace2 name>
labels:
<label key>: <label value>
policies:
- name: <policy1 name>
rules:
- name: <rule1 name>
values:
<context variable1 in policy1 rule1>: <value>
<context variable2 in policy1 rule1>: <value>
- name: <rule2 name>
values:
<context variable1 in policy1 rule2>: <value>
<context variable2 in policy1 rule2>: <value>
resources:
- name: <resource1 name>
values:
<variable1 in policy1>: <value>
<variable2 in policy1>: <value>
- name: <resource2 name>
values:
<variable1 in policy1>: <value>
<variable2 in policy1>: <value>
- name: <policy2 name>
resources:
- name: <resource1 name>
values:
<variable1 in policy2>: <value>
<variable2 in policy2>: <value>
- name: <resource2 name>
values:
<variable1 in policy2>: <value>
<variable2 in policy2>: <value>
namespaceSelector:
- name: <namespace1 name>
labels:
<label key>: <label value>
- name: <namespace2 name>
labels:
<label key>: <label value>
# If policy is matching on Kind/Subresource, then this is required
subresources:
- subresource:

View file

@ -57,17 +57,3 @@ type ReportResult struct {
TestResults
Resources []*corev1.ObjectReference `json:"resources"`
}
type Resource struct {
Name string `json:"name"`
Values map[string]string `json:"values"`
}
type Policy struct {
Name string `json:"name"`
Resources []Resource `json:"resources"`
}
type Values struct {
Policies []Policy `json:"policies"`
}

View file

@ -16,6 +16,7 @@ import (
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
sanitizederror "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/sanitizedError"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/store"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/values"
"github.com/kyverno/kyverno/pkg/autogen"
"github.com/kyverno/kyverno/pkg/background/generate"
"github.com/kyverno/kyverno/pkg/clients/dclient"
@ -47,39 +48,6 @@ type ResultCounts struct {
Error int
Skip int
}
type Policy struct {
Name string `json:"name"`
Resources []Resource `json:"resources"`
Rules []Rule `json:"rules"`
}
type Rule struct {
Name string `json:"name"`
Values map[string]interface{} `json:"values"`
ForeachValues map[string][]interface{} `json:"foreachValues"`
}
type Values struct {
Policies []Policy `json:"policies"`
GlobalValues map[string]string `json:"globalValues"`
NamespaceSelectors []NamespaceSelector `json:"namespaceSelector"`
Subresources []Subresource `json:"subresources"`
}
type Resource struct {
Name string `json:"name"`
Values map[string]interface{} `json:"values"`
}
type Subresource struct {
APIResource metav1.APIResource `json:"subresource"`
ParentResource metav1.APIResource `json:"parentResource"`
}
type NamespaceSelector struct {
Name string `json:"name"`
Labels map[string]string `json:"labels"`
}
type ApplyPolicyConfig struct {
Policy kyvernov1.PolicyInterface
@ -97,7 +65,7 @@ type ApplyPolicyConfig struct {
RuleToCloneSourceResource map[string]string
Client dclient.Interface
AuditWarn bool
Subresources []Subresource
Subresources []values.Subresource
}
// HasVariables - check for variables in the policy
@ -236,17 +204,15 @@ func GetVariable(
fs billy.Filesystem,
isGit bool,
policyResourcePath string,
) (map[string]string, map[string]string, map[string]map[string]Resource, map[string]map[string]string, []Subresource, error) {
valuesMapResource := make(map[string]map[string]Resource)
valuesMapRule := make(map[string]map[string]Rule)
) (map[string]string, map[string]string, map[string]map[string]values.Resource, map[string]map[string]string, []values.Subresource, error) {
valuesMapResource := make(map[string]map[string]values.Resource)
valuesMapRule := make(map[string]map[string]values.Rule)
namespaceSelectorMap := make(map[string]map[string]string)
variables := make(map[string]string)
subresources := make([]Subresource, 0)
subresources := make([]values.Subresource, 0)
globalValMap := make(map[string]string)
reqObjVars := ""
var yamlFile []byte
var err error
for _, kvpair := range variablesString {
kvs := strings.Split(strings.Trim(kvpair, " "), "=")
if strings.Contains(kvs[0], "request.object") {
@ -259,54 +225,29 @@ func GetVariable(
}
if valuesFile != "" {
if isGit {
filep, err := fs.Open(filepath.Join(policyResourcePath, valuesFile))
if err != nil {
fmt.Printf("Unable to open variable file: %s. error: %s", valuesFile, err)
}
yamlFile, err = io.ReadAll(filep)
if err != nil {
fmt.Printf("Unable to read variable files: %s. error: %s \n", filep, err)
}
} else {
// We accept the risk of including a user provided file here.
yamlFile, err = os.ReadFile(filepath.Join(policyResourcePath, valuesFile)) // #nosec G304
if err != nil {
fmt.Printf("\n Unable to open variable file: %s. error: %s \n", valuesFile, err)
}
}
vals, err := values.Load(fs, filepath.Join(policyResourcePath, valuesFile))
if err != nil {
fmt.Printf("Unable to load variable file: %s. error: %s \n", valuesFile, err)
return variables, globalValMap, valuesMapResource, namespaceSelectorMap, subresources, sanitizederror.NewWithError("unable to read yaml", err)
}
valuesBytes, err := yaml.ToJSON(yamlFile)
if err != nil {
return variables, globalValMap, valuesMapResource, namespaceSelectorMap, subresources, sanitizederror.NewWithError("failed to convert json", err)
}
values := &Values{}
if err := json.Unmarshal(valuesBytes, values); err != nil {
return variables, globalValMap, valuesMapResource, namespaceSelectorMap, subresources, sanitizederror.NewWithError("failed to decode yaml", err)
}
if values.GlobalValues == nil {
values.GlobalValues = make(map[string]string)
values.GlobalValues["request.operation"] = "CREATE"
if vals.GlobalValues == nil {
vals.GlobalValues = make(map[string]string)
vals.GlobalValues["request.operation"] = "CREATE"
log.V(3).Info("Defaulting request.operation to CREATE")
} else {
if val, ok := values.GlobalValues["request.operation"]; ok {
if val, ok := vals.GlobalValues["request.operation"]; ok {
if val == "" {
values.GlobalValues["request.operation"] = "CREATE"
log.V(3).Info("Globally request.operation value provided by the user is empty, defaulting it to CREATE", "request.opearation: ", values.GlobalValues)
vals.GlobalValues["request.operation"] = "CREATE"
log.V(3).Info("Globally request.operation value provided by the user is empty, defaulting it to CREATE", "request.opearation: ", vals.GlobalValues)
}
}
}
globalValMap = values.GlobalValues
globalValMap = vals.GlobalValues
for _, p := range values.Policies {
resourceMap := make(map[string]Resource)
for _, p := range vals.Policies {
resourceMap := make(map[string]values.Resource)
for _, r := range p.Resources {
if val, ok := r.Values["request.operation"]; ok {
if val == "" {
@ -328,7 +269,7 @@ func GetVariable(
valuesMapResource[p.Name] = resourceMap
if p.Rules != nil {
ruleMap := make(map[string]Rule)
ruleMap := make(map[string]values.Rule)
for _, r := range p.Rules {
ruleMap[r.Name] = r
}
@ -336,11 +277,11 @@ func GetVariable(
}
}
for _, n := range values.NamespaceSelectors {
for _, n := range vals.NamespaceSelectors {
namespaceSelectorMap[n.Name] = n.Labels
}
subresources = values.Subresources
subresources = vals.Subresources
}
if reqObjVars != "" {
@ -721,10 +662,10 @@ func PrintMutatedPolicy(mutatedPolicies []kyvernov1.PolicyInterface) error {
return nil
}
func CheckVariableForPolicy(valuesMap map[string]map[string]Resource, globalValMap map[string]string, policyName string, resourceName string, resourceKind string, variables map[string]string, kindOnwhichPolicyIsApplied map[string]struct{}, variable string) (map[string]interface{}, error) {
func CheckVariableForPolicy(valuesMap map[string]map[string]values.Resource, globalValMap map[string]string, policyName string, resourceName string, resourceKind string, variables map[string]string, kindOnwhichPolicyIsApplied map[string]struct{}, variable string) (map[string]interface{}, error) {
// get values from file for this policy resource combination
thisPolicyResourceValues := make(map[string]interface{})
if len(valuesMap[policyName]) != 0 && !datautils.DeepEqual(valuesMap[policyName][resourceName], Resource{}) {
if len(valuesMap[policyName]) != 0 && !datautils.DeepEqual(valuesMap[policyName][resourceName], values.Resource{}) {
thisPolicyResourceValues = valuesMap[policyName][resourceName].Values
}
@ -751,7 +692,7 @@ func CheckVariableForPolicy(valuesMap map[string]map[string]Resource, globalValM
return thisPolicyResourceValues, nil
}
func GetKindsFromPolicy(policy kyvernov1.PolicyInterface, subresources []Subresource, dClient dclient.Interface) map[string]struct{} {
func GetKindsFromPolicy(policy kyvernov1.PolicyInterface, subresources []values.Subresource, dClient dclient.Interface) map[string]struct{} {
kindOnwhichPolicyIsApplied := make(map[string]struct{})
for _, rule := range autogen.ComputeRules(policy) {
for _, kind := range rule.MatchResources.ResourceDescription.Kinds {
@ -774,7 +715,7 @@ func GetKindsFromPolicy(policy kyvernov1.PolicyInterface, subresources []Subreso
return kindOnwhichPolicyIsApplied
}
func getKind(kind string, subresources []Subresource, dClient dclient.Interface) (string, error) {
func getKind(kind string, subresources []values.Subresource, dClient dclient.Interface) (string, error) {
group, version, kind, subresource := kubeutils.ParseKindSelector(kind)
if subresource == "" {
return kind, nil
@ -796,7 +737,7 @@ func getKind(kind string, subresources []Subresource, dClient dclient.Interface)
return kind, nil
}
func getSubresourceKind(groupVersion, parentKind, subresourceName string, subresources []Subresource) (string, error) {
func getSubresourceKind(groupVersion, parentKind, subresourceName string, subresources []values.Subresource) (string, error) {
for _, subresource := range subresources {
parentResourceGroupVersion := metav1.GroupVersion{
Group: subresource.ParentResource.Group,

View file

@ -4,6 +4,7 @@ import (
"testing"
"github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/values"
yamlutils "github.com/kyverno/kyverno/pkg/utils/yaml"
"gotest.tools/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -193,7 +194,7 @@ func Test_getSubresourceKind(t *testing.T) {
podAPIResource := metav1.APIResource{Name: "pods", SingularName: "", Namespaced: true, Kind: "Pod"}
podEvictionAPIResource := metav1.APIResource{Name: "pods/eviction", SingularName: "", Namespaced: true, Group: "policy", Version: "v1", Kind: "Eviction"}
subresources := []Subresource{
subresources := []values.Subresource{
{
APIResource: podEvictionAPIResource,
ParentResource: podAPIResource,

View file

@ -12,6 +12,7 @@ import (
"github.com/go-git/go-billy/v5"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/values"
"github.com/kyverno/kyverno/pkg/autogen"
"github.com/kyverno/kyverno/pkg/clients/dclient"
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
@ -69,7 +70,7 @@ func GetResources(
return resources, err
}
func whenClusterIsTrue(resourceTypes []schema.GroupVersionKind, subresourceMap map[schema.GroupVersionKind]Subresource, dClient dclient.Interface, namespace string, resourcePaths []string, policyReport bool) ([]*unstructured.Unstructured, error) {
func whenClusterIsTrue(resourceTypes []schema.GroupVersionKind, subresourceMap map[schema.GroupVersionKind]values.Subresource, dClient dclient.Interface, namespace string, resourcePaths []string, policyReport bool) ([]*unstructured.Unstructured, error) {
resources := make([]*unstructured.Unstructured, 0)
resourceMap, err := getResourcesOfTypeFromCluster(resourceTypes, subresourceMap, dClient, namespace)
if err != nil {
@ -194,7 +195,7 @@ func GetResource(resourceBytes []byte) ([]*unstructured.Unstructured, error) {
return resources, nil
}
func getResourcesOfTypeFromCluster(resourceTypes []schema.GroupVersionKind, subresourceMap map[schema.GroupVersionKind]Subresource, dClient dclient.Interface, namespace string) (map[string]*unstructured.Unstructured, error) {
func getResourcesOfTypeFromCluster(resourceTypes []schema.GroupVersionKind, subresourceMap map[schema.GroupVersionKind]values.Subresource, dClient dclient.Interface, namespace string) (map[string]*unstructured.Unstructured, error) {
r := make(map[string]*unstructured.Unstructured)
for _, kind := range resourceTypes {
resourceList, err := dClient.ListResource(context.TODO(), kind.GroupVersion().String(), kind.Kind, namespace, nil)
@ -323,9 +324,9 @@ func GetPatchedAndGeneratedResource(resourceBytes []byte) (unstructured.Unstruct
}
// GetKindsFromRule will return the kinds from policy match block
func GetKindsFromRule(rule kyvernov1.Rule, client dclient.Interface) (map[schema.GroupVersionKind]bool, map[schema.GroupVersionKind]Subresource) {
func GetKindsFromRule(rule kyvernov1.Rule, client dclient.Interface) (map[schema.GroupVersionKind]bool, map[schema.GroupVersionKind]values.Subresource) {
resourceTypesMap := make(map[schema.GroupVersionKind]bool)
subresourceMap := make(map[schema.GroupVersionKind]Subresource)
subresourceMap := make(map[schema.GroupVersionKind]values.Subresource)
for _, kind := range rule.MatchResources.Kinds {
addGVKToResourceTypesMap(kind, resourceTypesMap, subresourceMap, client)
}
@ -346,9 +347,9 @@ func GetKindsFromRule(rule kyvernov1.Rule, client dclient.Interface) (map[schema
return resourceTypesMap, subresourceMap
}
func getKindsFromValidatingAdmissionRule(rule admissionregistrationv1.Rule, client dclient.Interface) (map[schema.GroupVersionKind]bool, map[schema.GroupVersionKind]Subresource, error) {
func getKindsFromValidatingAdmissionRule(rule admissionregistrationv1.Rule, client dclient.Interface) (map[schema.GroupVersionKind]bool, map[schema.GroupVersionKind]values.Subresource, error) {
resourceTypesMap := make(map[schema.GroupVersionKind]bool)
subresourceMap := make(map[schema.GroupVersionKind]Subresource)
subresourceMap := make(map[schema.GroupVersionKind]values.Subresource)
group := rule.APIGroups[0]
if group == "" {
@ -388,7 +389,7 @@ func getKindsFromValidatingAdmissionRule(rule admissionregistrationv1.Rule, clie
gvk := schema.GroupVersionKind{
Group: child.Group, Version: child.Version, Kind: child.Kind,
}
subresourceMap[gvk] = Subresource{
subresourceMap[gvk] = values.Subresource{
APIResource: child,
ParentResource: metav1.APIResource{
Group: parent.Group,
@ -404,7 +405,7 @@ func getKindsFromValidatingAdmissionRule(rule admissionregistrationv1.Rule, clie
return resourceTypesMap, subresourceMap, nil
}
func addGVKToResourceTypesMap(kind string, resourceTypesMap map[schema.GroupVersionKind]bool, subresourceMap map[schema.GroupVersionKind]Subresource, client dclient.Interface) {
func addGVKToResourceTypesMap(kind string, resourceTypesMap map[schema.GroupVersionKind]bool, subresourceMap map[schema.GroupVersionKind]values.Subresource, client dclient.Interface) {
group, version, kind, subresource := kubeutils.ParseKindSelector(kind)
gvrss, err := client.Discovery().FindResources(group, version, kind, subresource)
if err != nil {
@ -419,7 +420,7 @@ func addGVKToResourceTypesMap(kind string, resourceTypesMap map[schema.GroupVers
gvk := schema.GroupVersionKind{
Group: child.Group, Version: child.Version, Kind: child.Kind,
}
subresourceMap[gvk] = Subresource{
subresourceMap[gvk] = values.Subresource{
APIResource: child,
ParentResource: metav1.APIResource{
Group: parent.Group,

View file

@ -2,6 +2,7 @@ package common
import (
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/values"
"github.com/kyverno/kyverno/pkg/autogen"
"github.com/kyverno/kyverno/pkg/clients/dclient"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@ -18,7 +19,7 @@ func (r *KyvernoResources) FetchResourcesFromPolicy(resourcePaths []string, dCli
resourceTypesMap := make(map[schema.GroupVersionKind]bool)
var resourceTypes []schema.GroupVersionKind
var subresourceMap map[schema.GroupVersionKind]Subresource
var subresourceMap map[schema.GroupVersionKind]values.Subresource
for _, policy := range r.policies {
for _, rule := range autogen.ComputeRules(policy) {

View file

@ -1,6 +1,7 @@
package common
import (
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/values"
"github.com/kyverno/kyverno/pkg/clients/dclient"
"k8s.io/api/admissionregistration/v1alpha1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@ -17,7 +18,7 @@ func (r *ValidatingAdmissionResources) FetchResourcesFromPolicy(resourcePaths []
resourceTypesMap := make(map[schema.GroupVersionKind]bool)
var resourceTypes []schema.GroupVersionKind
var subresourceMap map[schema.GroupVersionKind]Subresource
var subresourceMap map[schema.GroupVersionKind]values.Subresource
for _, policy := range r.policies {
for _, rule := range policy.Spec.MatchConstraints.ResourceRules {

View file

@ -0,0 +1,37 @@
package values
import (
"encoding/json"
"io"
"os"
"github.com/go-git/go-billy/v5"
"k8s.io/apimachinery/pkg/util/yaml"
)
func readFile(f billy.Filesystem, filepath string) ([]byte, error) {
if f != nil {
filep, err := f.Open(filepath)
if err != nil {
return nil, err
}
return io.ReadAll(filep)
}
return os.ReadFile(filepath)
}
func Load(f billy.Filesystem, filepath string) (*Values, error) {
yamlBytes, err := readFile(f, filepath)
if err != nil {
return nil, err
}
jsonBytes, err := yaml.ToJSON(yamlBytes)
if err != nil {
return nil, err
}
vals := &Values{}
if err := json.Unmarshal(jsonBytes, vals); err != nil {
return nil, err
}
return vals, nil
}

View file

@ -0,0 +1,39 @@
package values
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
type Policy struct {
Name string `json:"name"`
Resources []Resource `json:"resources"`
Rules []Rule `json:"rules"`
}
type Rule struct {
Name string `json:"name"`
Values map[string]interface{} `json:"values"`
ForeachValues map[string][]interface{} `json:"foreachValues"`
}
type Values struct {
Policies []Policy `json:"policies"`
GlobalValues map[string]string `json:"globalValues"`
NamespaceSelectors []NamespaceSelector `json:"namespaceSelector"`
Subresources []Subresource `json:"subresources"`
}
type Resource struct {
Name string `json:"name"`
Values map[string]interface{} `json:"values"`
}
type Subresource struct {
APIResource metav1.APIResource `json:"subresource"`
ParentResource metav1.APIResource `json:"parentResource"`
}
type NamespaceSelector struct {
Name string `json:"name"`
Labels map[string]string `json:"labels"`
}