1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00

feat(json): reduce reliance on DocumentToUntyped() (#10724)

Signed-off-by: Khaled Emara <khaled.emara@nirmata.com>
Co-authored-by: Mariam Fahmy <mariam.fahmy@nirmata.com>
This commit is contained in:
Khaled Emara 2024-07-29 14:57:20 +03:00 committed by GitHub
parent 70c1dc6a06
commit c2646f7a9d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 48 additions and 28 deletions

View file

@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"github.com/kyverno/kyverno/api/kyverno"
"github.com/kyverno/kyverno/pkg/engine/variables/regex"
"github.com/kyverno/kyverno/pkg/pss/utils"
"github.com/sigstore/k8s-manifest-sigstore/pkg/k8smanifest"
@ -119,7 +120,9 @@ type ContextEntry struct {
type Variable struct {
// Value is any arbitrary JSON object representable in YAML or JSON form.
// +optional
Value *apiextv1.JSON `json:"value,omitempty" yaml:"value,omitempty"`
// +kubebuilder:validation:Schemaless
// +kubebuilder:pruning:PreserveUnknownFields
Value *kyverno.Any `json:"value,omitempty" yaml:"value,omitempty"`
// JMESPath is an optional JMESPath Expression that can be used to
// transform the variable.
@ -129,7 +132,25 @@ type Variable struct {
// Default is an optional arbitrary JSON object that the variable may take if the JMESPath
// expression evaluates to nil
// +optional
Default *apiextv1.JSON `json:"default,omitempty" yaml:"default,omitempty"`
// +kubebuilder:validation:Schemaless
// +kubebuilder:pruning:PreserveUnknownFields
Default *kyverno.Any `json:"default,omitempty" yaml:"default,omitempty"`
}
func (v *Variable) GetValue() any {
return kyverno.FromAny(v.Value)
}
func (v *Variable) SetValue(in any) {
v.Value = kyverno.ToAny(in)
}
func (v *Variable) GetDefault() any {
return kyverno.FromAny(v.Default)
}
func (v *Variable) SetDefault(in any) {
v.Default = kyverno.ToAny(in)
}
// ImageRegistry defines requests to an OCI/Docker V2 registry to fetch image

View file

@ -1678,13 +1678,11 @@ func (in *Variable) DeepCopyInto(out *Variable) {
*out = *in
if in.Value != nil {
in, out := &in.Value, &out.Value
*out = new(apiextensionsv1.JSON)
(*in).DeepCopyInto(*out)
*out = (*in).DeepCopy()
}
if in.Default != nil {
in, out := &in.Default, &out.Default
*out = new(apiextensionsv1.JSON)
(*in).DeepCopyInto(*out)
*out = (*in).DeepCopy()
}
return
}

View file

@ -4593,9 +4593,7 @@ Kubernetes meta/v1.LabelSelector
<td>
<code>value</code><br/>
<em>
<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#json-v1-apiextensions">
Kubernetes apiextensions/v1.JSON
</a>
github.com/kyverno/kyverno/api/kyverno.Any
</em>
</td>
<td>
@ -4620,9 +4618,7 @@ transform the variable.</p>
<td>
<code>default</code><br/>
<em>
<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#json-v1-apiextensions">
Kubernetes apiextensions/v1.JSON
</a>
github.com/kyverno/kyverno/api/kyverno.Any
</em>
</td>
<td>

View file

@ -9213,7 +9213,7 @@ by specifying exclusions for Pod Security Standards controls.</p>
<span style="font-family: monospace">k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.JSON</span>
<span style="font-family: monospace">github.com/kyverno/kyverno/api/kyverno.Any</span>
</td>
@ -9268,7 +9268,7 @@ transform the variable.</p>
<span style="font-family: monospace">k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.JSON</span>
<span style="font-family: monospace">github.com/kyverno/kyverno/api/kyverno.Any</span>
</td>

View file

@ -19,15 +19,15 @@ limitations under the License.
package v1
import (
v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
kyverno "github.com/kyverno/kyverno/api/kyverno"
)
// VariableApplyConfiguration represents an declarative configuration of the Variable type for use
// with apply.
type VariableApplyConfiguration struct {
Value *v1.JSON `json:"value,omitempty"`
Value *kyverno.Any `json:"value,omitempty"`
JMESPath *string `json:"jmesPath,omitempty"`
Default *v1.JSON `json:"default,omitempty"`
Default *kyverno.Any `json:"default,omitempty"`
}
// VariableApplyConfiguration constructs an declarative configuration of the Variable type for use with
@ -39,7 +39,7 @@ func Variable() *VariableApplyConfiguration {
// WithValue sets the Value field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Value field is set to the value of the last call.
func (b *VariableApplyConfiguration) WithValue(value v1.JSON) *VariableApplyConfiguration {
func (b *VariableApplyConfiguration) WithValue(value kyverno.Any) *VariableApplyConfiguration {
b.Value = &value
return b
}
@ -55,7 +55,7 @@ func (b *VariableApplyConfiguration) WithJMESPath(value string) *VariableApplyCo
// WithDefault sets the Default field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Default field is set to the value of the last call.
func (b *VariableApplyConfiguration) WithDefault(value v1.JSON) *VariableApplyConfiguration {
func (b *VariableApplyConfiguration) WithDefault(value kyverno.Any) *VariableApplyConfiguration {
b.Default = &value
return b
}

View file

@ -62,24 +62,24 @@ func (vl *variableLoader) loadVariable() (err error) {
}
var defaultValue interface{} = nil
if entry.Variable.Default != nil {
value, err := jsonutils.DocumentToUntyped(entry.Variable.Default)
if entry.Variable.GetDefault() != nil {
value, err := jsonutils.DocumentToUntyped(entry.Variable.GetDefault())
if err != nil {
return fmt.Errorf("invalid default for variable %s", entry.Name)
}
defaultValue, err = variables.SubstituteAll(logger, ctx, value)
if err != nil {
return fmt.Errorf("failed to substitute variables in context entry %s %s: %v", entry.Name, entry.Variable.Default, err)
return fmt.Errorf("failed to substitute variables in context entry %s %s: %v", entry.Name, entry.Variable.GetDefault(), err)
}
logger.V(4).Info("evaluated default value", "variable name", entry.Name, "jmespath", defaultValue)
}
var output interface{} = defaultValue
if entry.Variable.Value != nil {
value, _ := jsonutils.DocumentToUntyped(entry.Variable.Value)
if entry.Variable.GetValue() != nil {
value, _ := jsonutils.DocumentToUntyped(entry.Variable.GetValue())
variable, err := variables.SubstituteAll(logger, ctx, value)
if err != nil {
return fmt.Errorf("failed to substitute variables in context entry %s %s: %v", entry.Name, entry.Variable.Value, err)
return fmt.Errorf("failed to substitute variables in context entry %s %s: %v", entry.Name, entry.Variable.GetValue(), err)
}
if path != "" {
variable, err := applyJMESPath(vl.jp, path, variable)

View file

@ -7,6 +7,11 @@ var json = jsoniter.ConfigCompatibleWithStandardLibrary
// DocumentToUntyped converts a typed object to JSON data
// i.e. string, []interface{}, map[string]interface{}
func DocumentToUntyped(doc interface{}) (interface{}, error) {
switch doc.(type) {
case string, []any, map[string]any:
return doc, nil
}
jsonDoc, err := json.Marshal(doc)
if err != nil {
return nil, err

View file

@ -1303,10 +1303,10 @@ func validateVariable(entry kyvernov1.ContextEntry) error {
return fmt.Errorf("failed to parse JMESPath %s: %v", entry.Variable.JMESPath, err)
}
}
if entry.Variable.Value == nil && jmesPath == "" {
if entry.Variable.GetValue() == nil && jmesPath == "" {
return fmt.Errorf("a variable must define a value or a jmesPath expression")
}
if entry.Variable.Default != nil && jmesPath == "" {
if entry.Variable.GetDefault() != nil && jmesPath == "" {
return fmt.Errorf("a variable must define a default value only when a jmesPath expression is defined")
}
return nil