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:
parent
70c1dc6a06
commit
c2646f7a9d
8 changed files with 48 additions and 28 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue