mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-28 18:38:40 +00:00
feat(json): unmarshal once per policy (#10701)
Signed-off-by: Khaled Emara <khaled.emara@nirmata.com> Co-authored-by: Mariam Fahmy <mariam.fahmy@nirmata.com> Co-authored-by: shuting <shuting@nirmata.com>
This commit is contained in:
parent
74e17cc629
commit
d173752041
14 changed files with 345 additions and 77 deletions
|
@ -427,7 +427,16 @@ type ForEachMutation struct {
|
|||
|
||||
// Foreach declares a nested foreach iterator
|
||||
// +optional
|
||||
ForEachMutation *apiextv1.JSON `json:"foreach,omitempty" yaml:"foreach,omitempty"`
|
||||
// +kubebuilder:validation:Schemaless
|
||||
// +kubebuilder:pruning:PreserveUnknownFields
|
||||
ForEachMutation *ForEachMutationWrapper `json:"foreach,omitempty" yaml:"foreach,omitempty"`
|
||||
}
|
||||
|
||||
func (m *ForEachMutation) GetForEachMutation() []ForEachMutation {
|
||||
if m.ForEachMutation == nil {
|
||||
return nil
|
||||
}
|
||||
return m.ForEachMutation.Items
|
||||
}
|
||||
|
||||
func (m *ForEachMutation) GetPatchStrategicMerge() apiextensions.JSON {
|
||||
|
@ -690,7 +699,16 @@ type ForEachValidation struct {
|
|||
|
||||
// Foreach declares a nested foreach iterator
|
||||
// +optional
|
||||
ForEachValidation *apiextv1.JSON `json:"foreach,omitempty" yaml:"foreach,omitempty"`
|
||||
// +kubebuilder:validation:Schemaless
|
||||
// +kubebuilder:pruning:PreserveUnknownFields
|
||||
ForEachValidation *ForEachValidationWrapper `json:"foreach,omitempty" yaml:"foreach,omitempty"`
|
||||
}
|
||||
|
||||
func (v *ForEachValidation) GetForEachValidation() []ForEachValidation {
|
||||
if v.ForEachValidation == nil {
|
||||
return nil
|
||||
}
|
||||
return v.ForEachValidation.Items
|
||||
}
|
||||
|
||||
func (v *ForEachValidation) GetPattern() apiextensions.JSON {
|
||||
|
|
79
api/kyverno/v1/wrappers.go
Normal file
79
api/kyverno/v1/wrappers.go
Normal file
|
@ -0,0 +1,79 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/jinzhu/copier"
|
||||
)
|
||||
|
||||
// ForEachValidationWrapper contains a list of ForEach descriptors.
|
||||
// +k8s:deepcopy-gen=false
|
||||
type ForEachValidationWrapper struct {
|
||||
// Item is a descriptor on how to iterate over the list of items.
|
||||
// +optional
|
||||
Items []ForEachValidation `json:"-"`
|
||||
}
|
||||
|
||||
func (in *ForEachValidationWrapper) DeepCopyInto(out *ForEachValidationWrapper) {
|
||||
if err := copier.Copy(out, in); err != nil {
|
||||
panic("deep copy failed")
|
||||
}
|
||||
}
|
||||
|
||||
func (in *ForEachValidationWrapper) DeepCopy() *ForEachValidationWrapper {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ForEachValidationWrapper)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
func (a *ForEachValidationWrapper) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(a.Items)
|
||||
}
|
||||
|
||||
func (a *ForEachValidationWrapper) UnmarshalJSON(data []byte) error {
|
||||
var res []ForEachValidation
|
||||
if err := json.Unmarshal(data, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
a.Items = res
|
||||
return nil
|
||||
}
|
||||
|
||||
// ForEachMutationWrapper contains a list of ForEach descriptors.
|
||||
// +k8s:deepcopy-gen=false
|
||||
type ForEachMutationWrapper struct {
|
||||
// Item is a descriptor on how to iterate over the list of items.
|
||||
// +optional
|
||||
Items []ForEachMutation `json:"-"`
|
||||
}
|
||||
|
||||
func (in *ForEachMutationWrapper) DeepCopyInto(out *ForEachMutationWrapper) {
|
||||
if err := copier.Copy(out, in); err != nil {
|
||||
panic("deep copy failed")
|
||||
}
|
||||
}
|
||||
|
||||
func (in *ForEachMutationWrapper) DeepCopy() *ForEachMutationWrapper {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ForEachMutationWrapper)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
func (a *ForEachMutationWrapper) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(a.Items)
|
||||
}
|
||||
|
||||
func (a *ForEachMutationWrapper) UnmarshalJSON(data []byte) error {
|
||||
var res []ForEachMutation
|
||||
if err := json.Unmarshal(data, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
a.Items = res
|
||||
return nil
|
||||
}
|
|
@ -565,8 +565,7 @@ func (in *ForEachMutation) DeepCopyInto(out *ForEachMutation) {
|
|||
}
|
||||
if in.ForEachMutation != nil {
|
||||
in, out := &in.ForEachMutation, &out.ForEachMutation
|
||||
*out = new(apiextensionsv1.JSON)
|
||||
(*in).DeepCopyInto(*out)
|
||||
*out = (*in).DeepCopy()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -618,8 +617,7 @@ func (in *ForEachValidation) DeepCopyInto(out *ForEachValidation) {
|
|||
}
|
||||
if in.ForEachValidation != nil {
|
||||
in, out := &in.ForEachValidation, &out.ForEachValidation
|
||||
*out = new(apiextensionsv1.JSON)
|
||||
(*in).DeepCopyInto(*out)
|
||||
*out = (*in).DeepCopy()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1615,6 +1615,7 @@ string
|
|||
</h3>
|
||||
<p>
|
||||
(<em>Appears on:</em>
|
||||
<a href="#kyverno.io/v1.ForEachMutationWrapper">ForEachMutationWrapper</a>,
|
||||
<a href="#kyverno.io/v1.Mutation">Mutation</a>)
|
||||
</p>
|
||||
<p>
|
||||
|
@ -1718,8 +1719,8 @@ See <a href="https://tools.ietf.org/html/rfc6902">https://tools.ietf.org/html/rf
|
|||
<td>
|
||||
<code>foreach</code><br/>
|
||||
<em>
|
||||
<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#json-v1-apiextensions">
|
||||
Kubernetes apiextensions/v1.JSON
|
||||
<a href="#kyverno.io/v1.ForEachMutationWrapper">
|
||||
ForEachMutationWrapper
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
|
@ -1731,10 +1732,45 @@ Kubernetes apiextensions/v1.JSON
|
|||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h3 id="kyverno.io/v1.ForEachMutationWrapper">ForEachMutationWrapper
|
||||
</h3>
|
||||
<p>
|
||||
(<em>Appears on:</em>
|
||||
<a href="#kyverno.io/v1.ForEachMutation">ForEachMutation</a>)
|
||||
</p>
|
||||
<p>
|
||||
<p>ForEachMutationWrapper contains a list of ForEach descriptors.</p>
|
||||
</p>
|
||||
<table class="table table-striped">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>-</code><br/>
|
||||
<em>
|
||||
<a href="#kyverno.io/v1.ForEachMutation">
|
||||
[]ForEachMutation
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Item is a descriptor on how to iterate over the list of items.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h3 id="kyverno.io/v1.ForEachValidation">ForEachValidation
|
||||
</h3>
|
||||
<p>
|
||||
(<em>Appears on:</em>
|
||||
<a href="#kyverno.io/v1.ForEachValidationWrapper">ForEachValidationWrapper</a>,
|
||||
<a href="#kyverno.io/v1.Validation">Validation</a>,
|
||||
<a href="#kyverno.io/v2beta1.Validation">Validation</a>)
|
||||
</p>
|
||||
|
@ -1852,8 +1888,8 @@ Deny
|
|||
<td>
|
||||
<code>foreach</code><br/>
|
||||
<em>
|
||||
<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#json-v1-apiextensions">
|
||||
Kubernetes apiextensions/v1.JSON
|
||||
<a href="#kyverno.io/v1.ForEachValidationWrapper">
|
||||
ForEachValidationWrapper
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
|
@ -1865,6 +1901,40 @@ Kubernetes apiextensions/v1.JSON
|
|||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h3 id="kyverno.io/v1.ForEachValidationWrapper">ForEachValidationWrapper
|
||||
</h3>
|
||||
<p>
|
||||
(<em>Appears on:</em>
|
||||
<a href="#kyverno.io/v1.ForEachValidation">ForEachValidation</a>)
|
||||
</p>
|
||||
<p>
|
||||
<p>ForEachValidationWrapper contains a list of ForEach descriptors.</p>
|
||||
</p>
|
||||
<table class="table table-striped">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>-</code><br/>
|
||||
<em>
|
||||
<a href="#kyverno.io/v1.ForEachValidation">
|
||||
[]ForEachValidation
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Item is a descriptor on how to iterate over the list of items.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h3 id="kyverno.io/v1.ForeachOrder">ForeachOrder
|
||||
(<code>string</code> alias)</p></h3>
|
||||
<p>
|
||||
|
|
|
@ -3318,6 +3318,7 @@ Dryrun requires additional permissions. See config/dryrun/dryrun_rbac.yaml</p>
|
|||
|
||||
<p>
|
||||
(<em>Appears in:</em>
|
||||
<a href="#kyverno-io-v1-ForEachMutationWrapper">ForEachMutationWrapper</a>,
|
||||
<a href="#kyverno-io-v1-Mutation">Mutation</a>)
|
||||
</p>
|
||||
|
||||
|
@ -3529,7 +3530,9 @@ See https://tools.ietf.org/html/rfc6902 and https://kubectl.docs.kubernetes.io/r
|
|||
|
||||
|
||||
|
||||
<span style="font-family: monospace">k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.JSON</span>
|
||||
<a href="#kyverno-io-v1-ForEachMutationWrapper">
|
||||
<span style="font-family: monospace">ForEachMutationWrapper</span>
|
||||
</a>
|
||||
|
||||
|
||||
</td>
|
||||
|
@ -3548,6 +3551,71 @@ See https://tools.ietf.org/html/rfc6902 and https://kubectl.docs.kubernetes.io/r
|
|||
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<H3 id="kyverno-io-v1-ForEachMutationWrapper">ForEachMutationWrapper
|
||||
</H3>
|
||||
|
||||
|
||||
<p>
|
||||
(<em>Appears in:</em>
|
||||
<a href="#kyverno-io-v1-ForEachMutation">ForEachMutation</a>)
|
||||
</p>
|
||||
|
||||
|
||||
<p><p>ForEachMutationWrapper contains a list of ForEach descriptors.</p>
|
||||
</p>
|
||||
|
||||
|
||||
<table class="table table-striped">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
<td><code>-</code>
|
||||
|
||||
</br>
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="#kyverno-io-v1-ForEachMutation">
|
||||
<span style="font-family: monospace">[]ForEachMutation</span>
|
||||
</a>
|
||||
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
|
||||
<p>Item is a descriptor on how to iterate over the list of items.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
@ -3558,6 +3626,7 @@ See https://tools.ietf.org/html/rfc6902 and https://kubectl.docs.kubernetes.io/r
|
|||
|
||||
<p>
|
||||
(<em>Appears in:</em>
|
||||
<a href="#kyverno-io-v1-ForEachValidationWrapper">ForEachValidationWrapper</a>,
|
||||
<a href="#kyverno-io-v1-Validation">Validation</a>)
|
||||
</p>
|
||||
|
||||
|
@ -3795,7 +3864,9 @@ must be satisfied for the validation rule to succeed.</p>
|
|||
|
||||
|
||||
|
||||
<span style="font-family: monospace">k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.JSON</span>
|
||||
<a href="#kyverno-io-v1-ForEachValidationWrapper">
|
||||
<span style="font-family: monospace">ForEachValidationWrapper</span>
|
||||
</a>
|
||||
|
||||
|
||||
</td>
|
||||
|
@ -3814,6 +3885,71 @@ must be satisfied for the validation rule to succeed.</p>
|
|||
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<H3 id="kyverno-io-v1-ForEachValidationWrapper">ForEachValidationWrapper
|
||||
</H3>
|
||||
|
||||
|
||||
<p>
|
||||
(<em>Appears in:</em>
|
||||
<a href="#kyverno-io-v1-ForEachValidation">ForEachValidation</a>)
|
||||
</p>
|
||||
|
||||
|
||||
<p><p>ForEachValidationWrapper contains a list of ForEach descriptors.</p>
|
||||
</p>
|
||||
|
||||
|
||||
<table class="table table-striped">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
<td><code>-</code>
|
||||
|
||||
</br>
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="#kyverno-io-v1-ForEachValidation">
|
||||
<span style="font-family: monospace">[]ForEachValidation</span>
|
||||
</a>
|
||||
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
|
||||
<p>Item is a descriptor on how to iterate over the list of items.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ type ForEachMutationApplyConfiguration struct {
|
|||
AnyAllConditions *AnyAllConditionsApplyConfiguration `json:"preconditions,omitempty"`
|
||||
RawPatchStrategicMerge *apiextensionsv1.JSON `json:"patchStrategicMerge,omitempty"`
|
||||
PatchesJSON6902 *string `json:"patchesJson6902,omitempty"`
|
||||
ForEachMutation *apiextensionsv1.JSON `json:"foreach,omitempty"`
|
||||
ForEachMutation *v1.ForEachMutationWrapper `json:"foreach,omitempty"`
|
||||
}
|
||||
|
||||
// ForEachMutationApplyConfiguration constructs an declarative configuration of the ForEachMutation type for use with
|
||||
|
@ -97,7 +97,7 @@ func (b *ForEachMutationApplyConfiguration) WithPatchesJSON6902(value string) *F
|
|||
// WithForEachMutation sets the ForEachMutation 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 ForEachMutation field is set to the value of the last call.
|
||||
func (b *ForEachMutationApplyConfiguration) WithForEachMutation(value apiextensionsv1.JSON) *ForEachMutationApplyConfiguration {
|
||||
func (b *ForEachMutationApplyConfiguration) WithForEachMutation(value v1.ForEachMutationWrapper) *ForEachMutationApplyConfiguration {
|
||||
b.ForEachMutation = &value
|
||||
return b
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ limitations under the License.
|
|||
package v1
|
||||
|
||||
import (
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
)
|
||||
|
||||
|
@ -32,7 +33,7 @@ type ForEachValidationApplyConfiguration struct {
|
|||
RawPattern *apiextensionsv1.JSON `json:"pattern,omitempty"`
|
||||
RawAnyPattern *apiextensionsv1.JSON `json:"anyPattern,omitempty"`
|
||||
Deny *DenyApplyConfiguration `json:"deny,omitempty"`
|
||||
ForEachValidation *apiextensionsv1.JSON `json:"foreach,omitempty"`
|
||||
ForEachValidation *kyvernov1.ForEachValidationWrapper `json:"foreach,omitempty"`
|
||||
}
|
||||
|
||||
// ForEachValidationApplyConfiguration constructs an declarative configuration of the ForEachValidation type for use with
|
||||
|
@ -105,7 +106,7 @@ func (b *ForEachValidationApplyConfiguration) WithDeny(value *DenyApplyConfigura
|
|||
// WithForEachValidation sets the ForEachValidation 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 ForEachValidation field is set to the value of the last call.
|
||||
func (b *ForEachValidationApplyConfiguration) WithForEachValidation(value apiextensionsv1.JSON) *ForEachValidationApplyConfiguration {
|
||||
func (b *ForEachValidationApplyConfiguration) WithForEachValidation(value kyvernov1.ForEachValidationWrapper) *ForEachValidationApplyConfiguration {
|
||||
b.ForEachValidation = &value
|
||||
return b
|
||||
}
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
package engine
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/engine/context"
|
||||
"github.com/kyverno/kyverno/pkg/engine/internal"
|
||||
"github.com/kyverno/kyverno/pkg/engine/mutate"
|
||||
"github.com/kyverno/kyverno/pkg/engine/variables"
|
||||
"github.com/kyverno/kyverno/pkg/utils/api"
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
@ -64,13 +61,9 @@ func ForceMutate(
|
|||
func applyForEachMutate(name string, foreach []kyvernov1.ForEachMutation, resource unstructured.Unstructured, logger logr.Logger) (patchedResource unstructured.Unstructured, err error) {
|
||||
patchedResource = resource
|
||||
for _, fe := range foreach {
|
||||
if fe.ForEachMutation != nil {
|
||||
nestedForEach, err := api.DeserializeJSONArray[kyvernov1.ForEachMutation](fe.ForEachMutation)
|
||||
if err != nil {
|
||||
return patchedResource, fmt.Errorf("failed to deserialize foreach: %w", err)
|
||||
}
|
||||
|
||||
return applyForEachMutate(name, nestedForEach, patchedResource, logger)
|
||||
fem := fe.GetForEachMutation()
|
||||
if len(fem) > 0 {
|
||||
return applyForEachMutate(name, fem, patchedResource, logger)
|
||||
}
|
||||
|
||||
patchedResource, err = applyPatches(fe.GetPatchStrategicMerge(), fe.PatchesJSON6902, patchedResource, logger)
|
||||
|
|
|
@ -11,7 +11,6 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/engine/internal"
|
||||
"github.com/kyverno/kyverno/pkg/engine/mutate"
|
||||
engineutils "github.com/kyverno/kyverno/pkg/engine/utils"
|
||||
"github.com/kyverno/kyverno/pkg/utils/api"
|
||||
datautils "github.com/kyverno/kyverno/pkg/utils/data"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
@ -110,18 +109,14 @@ func (f *forEachMutator) mutateElements(ctx context.Context, foreach kyvernov1.F
|
|||
}
|
||||
|
||||
var mutateResp *mutate.Response
|
||||
if foreach.ForEachMutation != nil {
|
||||
nestedForEach, err := api.DeserializeJSONArray[kyvernov1.ForEachMutation](foreach.ForEachMutation)
|
||||
if err != nil {
|
||||
return mutate.NewErrorResponse("failed to deserialize foreach", err)
|
||||
}
|
||||
|
||||
fem := foreach.GetForEachMutation()
|
||||
if len(fem) > 0 {
|
||||
m := &forEachMutator{
|
||||
rule: f.rule,
|
||||
policyContext: f.policyContext,
|
||||
resource: patchedResource,
|
||||
logger: f.logger,
|
||||
foreach: nestedForEach,
|
||||
foreach: fem,
|
||||
nesting: f.nesting + 1,
|
||||
contextLoader: f.contextLoader,
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ import (
|
|||
engineutils "github.com/kyverno/kyverno/pkg/engine/utils"
|
||||
"github.com/kyverno/kyverno/pkg/engine/validate"
|
||||
"github.com/kyverno/kyverno/pkg/engine/variables"
|
||||
"github.com/kyverno/kyverno/pkg/utils/api"
|
||||
datautils "github.com/kyverno/kyverno/pkg/utils/data"
|
||||
stringutils "github.com/kyverno/kyverno/pkg/utils/strings"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -103,9 +102,12 @@ func newForEachValidator(
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to convert ruleCopy.Validation.ForEachValidation.AnyAllConditions: %w", err)
|
||||
}
|
||||
nestedForEach, err := api.DeserializeJSONArray[kyvernov1.ForEachValidation](foreach.ForEachValidation)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to convert ruleCopy.Validation.ForEachValidation.AnyAllConditions: %w", err)
|
||||
var loopItems []kyvernov1.ForEachValidation
|
||||
fev := foreach.GetForEachValidation()
|
||||
if len(fev) > 0 {
|
||||
loopItems = fev
|
||||
} else {
|
||||
loopItems = make([]kyvernov1.ForEachValidation, 0)
|
||||
}
|
||||
return &validator{
|
||||
log: log,
|
||||
|
@ -117,7 +119,7 @@ func newForEachValidator(
|
|||
pattern: foreach.GetPattern(),
|
||||
anyPattern: foreach.GetAnyPattern(),
|
||||
deny: foreach.Deny,
|
||||
forEach: nestedForEach,
|
||||
forEach: loopItems,
|
||||
nesting: nesting,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -8,10 +8,8 @@ import (
|
|||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/engine/variables/regex"
|
||||
"github.com/kyverno/kyverno/pkg/policy/auth"
|
||||
"github.com/kyverno/kyverno/pkg/utils/api"
|
||||
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
||||
"go.uber.org/multierr"
|
||||
v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
)
|
||||
|
||||
// Mutate provides implementation to validate 'mutate' rule
|
||||
|
@ -55,12 +53,13 @@ func (m *Mutate) Validate(ctx context.Context) (string, error) {
|
|||
func (m *Mutate) validateForEach(tag string, foreach []kyvernov1.ForEachMutation) (string, error) {
|
||||
for i, fe := range foreach {
|
||||
tag = tag + fmt.Sprintf("foreach[%d]", i)
|
||||
if fe.ForEachMutation != nil {
|
||||
fem := fe.GetForEachMutation()
|
||||
if len(fem) > 0 {
|
||||
if fe.Context != nil || fe.AnyAllConditions != nil || fe.PatchesJSON6902 != "" || fe.RawPatchStrategicMerge != nil {
|
||||
return tag, fmt.Errorf("a nested foreach cannot contain other declarations")
|
||||
}
|
||||
|
||||
return m.validateNestedForEach(tag, fe.ForEachMutation)
|
||||
return m.validateNestedForEach(tag, fem)
|
||||
}
|
||||
|
||||
psm := fe.GetPatchStrategicMerge()
|
||||
|
@ -72,13 +71,12 @@ func (m *Mutate) validateForEach(tag string, foreach []kyvernov1.ForEachMutation
|
|||
return "", nil
|
||||
}
|
||||
|
||||
func (m *Mutate) validateNestedForEach(tag string, j *v1.JSON) (string, error) {
|
||||
nestedForeach, err := api.DeserializeJSONArray[kyvernov1.ForEachMutation](j)
|
||||
if err != nil {
|
||||
return tag, fmt.Errorf("invalid foreach syntax: %w", err)
|
||||
func (m *Mutate) validateNestedForEach(tag string, j []kyvernov1.ForEachMutation) (string, error) {
|
||||
if j != nil {
|
||||
return m.validateForEach(tag, j)
|
||||
}
|
||||
|
||||
return m.validateForEach(tag, nestedForeach)
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (m *Mutate) hasForEach() bool {
|
||||
|
|
|
@ -204,7 +204,7 @@ func foreachElemCount(foreach kyvernov1.ForEachValidation) int {
|
|||
count++
|
||||
}
|
||||
|
||||
if foreach.ForEachValidation != nil {
|
||||
if foreach.GetForEachValidation() != nil && len(foreach.GetForEachValidation()) > 0 {
|
||||
count++
|
||||
}
|
||||
|
||||
|
|
|
@ -8,22 +8,6 @@ import (
|
|||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||
)
|
||||
|
||||
// Deserialize "apiextensions.JSON" to a typed array
|
||||
func DeserializeJSONArray[T any](in apiextensions.JSON) ([]T, error) {
|
||||
if in == nil {
|
||||
return nil, nil
|
||||
}
|
||||
data, err := json.Marshal(in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var res []T
|
||||
if err := json.Unmarshal(data, &res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// ApiextensionsJsonToKyvernoConditions takes in user-provided conditions in abstract apiextensions.JSON form
|
||||
// and converts it into []kyverno.Condition or kyverno.AnyAllConditions according to its content.
|
||||
// it also helps in validating the condtions as it returns an error when the conditions are provided wrongfully by the user.
|
||||
|
|
|
@ -1002,12 +1002,9 @@ func validateValidationForEach(foreach []kyvernov1.ForEachValidation, schemaKey
|
|||
}
|
||||
}
|
||||
}
|
||||
if fe.ForEachValidation != nil {
|
||||
nestedForEach, err := apiutils.DeserializeJSONArray[kyvernov1.ForEachValidation](fe.ForEachValidation)
|
||||
if err != nil {
|
||||
return schemaKey, err
|
||||
}
|
||||
if path, err := validateValidationForEach(nestedForEach, schemaKey); err != nil {
|
||||
fev := fe.GetForEachValidation()
|
||||
if len(fev) > 0 {
|
||||
if path, err := validateValidationForEach(fev, schemaKey); err != nil {
|
||||
return fmt.Sprintf("%s.%s", schemaKey, path), err
|
||||
}
|
||||
}
|
||||
|
@ -1022,12 +1019,9 @@ func validateMutationForEach(foreach []kyvernov1.ForEachMutation, schemaKey stri
|
|||
return fmt.Sprintf("%s.%s", schemaKey, path), err
|
||||
}
|
||||
}
|
||||
if fe.ForEachMutation != nil {
|
||||
nestedForEach, err := apiutils.DeserializeJSONArray[kyvernov1.ForEachMutation](fe.ForEachMutation)
|
||||
if err != nil {
|
||||
return schemaKey, err
|
||||
}
|
||||
if path, err := validateMutationForEach(nestedForEach, schemaKey); err != nil {
|
||||
fem := fe.GetForEachMutation()
|
||||
if len(fem) > 0 {
|
||||
if path, err := validateMutationForEach(fem, schemaKey); err != nil {
|
||||
return fmt.Sprintf("%s.%s", schemaKey, path), err
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue