Merge pull request #115668 from jiahuif-forks/feature/validating-admission-policy/type-system
Type System for ValidatingAdmissionPolicy
This commit is contained in:
@@ -123,6 +123,52 @@ type ValidatingAdmissionPolicy struct {
|
||||
metav1.ObjectMeta
|
||||
// Specification of the desired behavior of the ValidatingAdmissionPolicy.
|
||||
Spec ValidatingAdmissionPolicySpec
|
||||
// The status of the ValidatingAdmissionPolicy, including warnings that are useful to determine if the policy
|
||||
// behaves in the expected way.
|
||||
// Populated by the system.
|
||||
// Read-only.
|
||||
// +optional
|
||||
Status ValidatingAdmissionPolicyStatus
|
||||
}
|
||||
|
||||
// ValidatingAdmissionPolicyStatus represents the status of an admission validation policy.
|
||||
type ValidatingAdmissionPolicyStatus struct {
|
||||
// The generation observed by the controller.
|
||||
// +optional
|
||||
ObservedGeneration int64
|
||||
// The results of type checking for each expression.
|
||||
// Presence of this field indicates the completion of the type checking.
|
||||
// +optional
|
||||
TypeChecking *TypeChecking
|
||||
// The conditions represent the latest available observations of a policy's current state.
|
||||
// +optional
|
||||
// +listType=map
|
||||
// +listMapKey=type
|
||||
Conditions []metav1.Condition
|
||||
}
|
||||
|
||||
// ValidatingAdmissionPolicyConditionType is the condition type of admission validation policy.
|
||||
type ValidatingAdmissionPolicyConditionType string
|
||||
|
||||
// TypeChecking contains results of type checking the expressions in the
|
||||
// ValidatingAdmissionPolicy
|
||||
type TypeChecking struct {
|
||||
// The type checking warnings for each expression.
|
||||
// +optional
|
||||
// +listType=atomic
|
||||
ExpressionWarnings []ExpressionWarning
|
||||
}
|
||||
|
||||
// ExpressionWarning is a warning information that targets a specific expression.
|
||||
type ExpressionWarning struct {
|
||||
// The path to the field that refers the expression.
|
||||
// For example, the reference to the expression of the first item of
|
||||
// validations is "spec.validations[0].expression"
|
||||
FieldRef string
|
||||
// The content of type checking information in a human-readable form.
|
||||
// Each line of the warning contains the type that the expression is checked
|
||||
// against, followed by the type check error from the compiler.
|
||||
Warning string
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
@@ -49,6 +49,16 @@ func RegisterConversions(s *runtime.Scheme) error {
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v1alpha1.ExpressionWarning)(nil), (*admissionregistration.ExpressionWarning)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1alpha1_ExpressionWarning_To_admissionregistration_ExpressionWarning(a.(*v1alpha1.ExpressionWarning), b.(*admissionregistration.ExpressionWarning), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*admissionregistration.ExpressionWarning)(nil), (*v1alpha1.ExpressionWarning)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_admissionregistration_ExpressionWarning_To_v1alpha1_ExpressionWarning(a.(*admissionregistration.ExpressionWarning), b.(*v1alpha1.ExpressionWarning), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v1alpha1.MatchResources)(nil), (*admissionregistration.MatchResources)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1alpha1_MatchResources_To_admissionregistration_MatchResources(a.(*v1alpha1.MatchResources), b.(*admissionregistration.MatchResources), scope)
|
||||
}); err != nil {
|
||||
@@ -89,6 +99,16 @@ func RegisterConversions(s *runtime.Scheme) error {
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v1alpha1.TypeChecking)(nil), (*admissionregistration.TypeChecking)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1alpha1_TypeChecking_To_admissionregistration_TypeChecking(a.(*v1alpha1.TypeChecking), b.(*admissionregistration.TypeChecking), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*admissionregistration.TypeChecking)(nil), (*v1alpha1.TypeChecking)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_admissionregistration_TypeChecking_To_v1alpha1_TypeChecking(a.(*admissionregistration.TypeChecking), b.(*v1alpha1.TypeChecking), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v1alpha1.ValidatingAdmissionPolicy)(nil), (*admissionregistration.ValidatingAdmissionPolicy)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1alpha1_ValidatingAdmissionPolicy_To_admissionregistration_ValidatingAdmissionPolicy(a.(*v1alpha1.ValidatingAdmissionPolicy), b.(*admissionregistration.ValidatingAdmissionPolicy), scope)
|
||||
}); err != nil {
|
||||
@@ -149,6 +169,16 @@ func RegisterConversions(s *runtime.Scheme) error {
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v1alpha1.ValidatingAdmissionPolicyStatus)(nil), (*admissionregistration.ValidatingAdmissionPolicyStatus)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1alpha1_ValidatingAdmissionPolicyStatus_To_admissionregistration_ValidatingAdmissionPolicyStatus(a.(*v1alpha1.ValidatingAdmissionPolicyStatus), b.(*admissionregistration.ValidatingAdmissionPolicyStatus), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*admissionregistration.ValidatingAdmissionPolicyStatus)(nil), (*v1alpha1.ValidatingAdmissionPolicyStatus)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_admissionregistration_ValidatingAdmissionPolicyStatus_To_v1alpha1_ValidatingAdmissionPolicyStatus(a.(*admissionregistration.ValidatingAdmissionPolicyStatus), b.(*v1alpha1.ValidatingAdmissionPolicyStatus), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v1alpha1.Validation)(nil), (*admissionregistration.Validation)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1alpha1_Validation_To_admissionregistration_Validation(a.(*v1alpha1.Validation), b.(*admissionregistration.Validation), scope)
|
||||
}); err != nil {
|
||||
@@ -184,6 +214,28 @@ func Convert_admissionregistration_AuditAnnotation_To_v1alpha1_AuditAnnotation(i
|
||||
return autoConvert_admissionregistration_AuditAnnotation_To_v1alpha1_AuditAnnotation(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_ExpressionWarning_To_admissionregistration_ExpressionWarning(in *v1alpha1.ExpressionWarning, out *admissionregistration.ExpressionWarning, s conversion.Scope) error {
|
||||
out.FieldRef = in.FieldRef
|
||||
out.Warning = in.Warning
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1alpha1_ExpressionWarning_To_admissionregistration_ExpressionWarning is an autogenerated conversion function.
|
||||
func Convert_v1alpha1_ExpressionWarning_To_admissionregistration_ExpressionWarning(in *v1alpha1.ExpressionWarning, out *admissionregistration.ExpressionWarning, s conversion.Scope) error {
|
||||
return autoConvert_v1alpha1_ExpressionWarning_To_admissionregistration_ExpressionWarning(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_admissionregistration_ExpressionWarning_To_v1alpha1_ExpressionWarning(in *admissionregistration.ExpressionWarning, out *v1alpha1.ExpressionWarning, s conversion.Scope) error {
|
||||
out.FieldRef = in.FieldRef
|
||||
out.Warning = in.Warning
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_admissionregistration_ExpressionWarning_To_v1alpha1_ExpressionWarning is an autogenerated conversion function.
|
||||
func Convert_admissionregistration_ExpressionWarning_To_v1alpha1_ExpressionWarning(in *admissionregistration.ExpressionWarning, out *v1alpha1.ExpressionWarning, s conversion.Scope) error {
|
||||
return autoConvert_admissionregistration_ExpressionWarning_To_v1alpha1_ExpressionWarning(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_MatchResources_To_admissionregistration_MatchResources(in *v1alpha1.MatchResources, out *admissionregistration.MatchResources, s conversion.Scope) error {
|
||||
out.NamespaceSelector = (*v1.LabelSelector)(unsafe.Pointer(in.NamespaceSelector))
|
||||
out.ObjectSelector = (*v1.LabelSelector)(unsafe.Pointer(in.ObjectSelector))
|
||||
@@ -322,11 +374,34 @@ func Convert_admissionregistration_ParamRef_To_v1alpha1_ParamRef(in *admissionre
|
||||
return autoConvert_admissionregistration_ParamRef_To_v1alpha1_ParamRef(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_TypeChecking_To_admissionregistration_TypeChecking(in *v1alpha1.TypeChecking, out *admissionregistration.TypeChecking, s conversion.Scope) error {
|
||||
out.ExpressionWarnings = *(*[]admissionregistration.ExpressionWarning)(unsafe.Pointer(&in.ExpressionWarnings))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1alpha1_TypeChecking_To_admissionregistration_TypeChecking is an autogenerated conversion function.
|
||||
func Convert_v1alpha1_TypeChecking_To_admissionregistration_TypeChecking(in *v1alpha1.TypeChecking, out *admissionregistration.TypeChecking, s conversion.Scope) error {
|
||||
return autoConvert_v1alpha1_TypeChecking_To_admissionregistration_TypeChecking(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_admissionregistration_TypeChecking_To_v1alpha1_TypeChecking(in *admissionregistration.TypeChecking, out *v1alpha1.TypeChecking, s conversion.Scope) error {
|
||||
out.ExpressionWarnings = *(*[]v1alpha1.ExpressionWarning)(unsafe.Pointer(&in.ExpressionWarnings))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_admissionregistration_TypeChecking_To_v1alpha1_TypeChecking is an autogenerated conversion function.
|
||||
func Convert_admissionregistration_TypeChecking_To_v1alpha1_TypeChecking(in *admissionregistration.TypeChecking, out *v1alpha1.TypeChecking, s conversion.Scope) error {
|
||||
return autoConvert_admissionregistration_TypeChecking_To_v1alpha1_TypeChecking(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_ValidatingAdmissionPolicy_To_admissionregistration_ValidatingAdmissionPolicy(in *v1alpha1.ValidatingAdmissionPolicy, out *admissionregistration.ValidatingAdmissionPolicy, s conversion.Scope) error {
|
||||
out.ObjectMeta = in.ObjectMeta
|
||||
if err := Convert_v1alpha1_ValidatingAdmissionPolicySpec_To_admissionregistration_ValidatingAdmissionPolicySpec(&in.Spec, &out.Spec, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Convert_v1alpha1_ValidatingAdmissionPolicyStatus_To_admissionregistration_ValidatingAdmissionPolicyStatus(&in.Status, &out.Status, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -340,6 +415,9 @@ func autoConvert_admissionregistration_ValidatingAdmissionPolicy_To_v1alpha1_Val
|
||||
if err := Convert_admissionregistration_ValidatingAdmissionPolicySpec_To_v1alpha1_ValidatingAdmissionPolicySpec(&in.Spec, &out.Spec, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Convert_admissionregistration_ValidatingAdmissionPolicyStatus_To_v1alpha1_ValidatingAdmissionPolicyStatus(&in.Status, &out.Status, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -544,6 +622,30 @@ func Convert_admissionregistration_ValidatingAdmissionPolicySpec_To_v1alpha1_Val
|
||||
return autoConvert_admissionregistration_ValidatingAdmissionPolicySpec_To_v1alpha1_ValidatingAdmissionPolicySpec(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_ValidatingAdmissionPolicyStatus_To_admissionregistration_ValidatingAdmissionPolicyStatus(in *v1alpha1.ValidatingAdmissionPolicyStatus, out *admissionregistration.ValidatingAdmissionPolicyStatus, s conversion.Scope) error {
|
||||
out.ObservedGeneration = in.ObservedGeneration
|
||||
out.TypeChecking = (*admissionregistration.TypeChecking)(unsafe.Pointer(in.TypeChecking))
|
||||
out.Conditions = *(*[]v1.Condition)(unsafe.Pointer(&in.Conditions))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1alpha1_ValidatingAdmissionPolicyStatus_To_admissionregistration_ValidatingAdmissionPolicyStatus is an autogenerated conversion function.
|
||||
func Convert_v1alpha1_ValidatingAdmissionPolicyStatus_To_admissionregistration_ValidatingAdmissionPolicyStatus(in *v1alpha1.ValidatingAdmissionPolicyStatus, out *admissionregistration.ValidatingAdmissionPolicyStatus, s conversion.Scope) error {
|
||||
return autoConvert_v1alpha1_ValidatingAdmissionPolicyStatus_To_admissionregistration_ValidatingAdmissionPolicyStatus(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_admissionregistration_ValidatingAdmissionPolicyStatus_To_v1alpha1_ValidatingAdmissionPolicyStatus(in *admissionregistration.ValidatingAdmissionPolicyStatus, out *v1alpha1.ValidatingAdmissionPolicyStatus, s conversion.Scope) error {
|
||||
out.ObservedGeneration = in.ObservedGeneration
|
||||
out.TypeChecking = (*v1alpha1.TypeChecking)(unsafe.Pointer(in.TypeChecking))
|
||||
out.Conditions = *(*[]v1.Condition)(unsafe.Pointer(&in.Conditions))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_admissionregistration_ValidatingAdmissionPolicyStatus_To_v1alpha1_ValidatingAdmissionPolicyStatus is an autogenerated conversion function.
|
||||
func Convert_admissionregistration_ValidatingAdmissionPolicyStatus_To_v1alpha1_ValidatingAdmissionPolicyStatus(in *admissionregistration.ValidatingAdmissionPolicyStatus, out *v1alpha1.ValidatingAdmissionPolicyStatus, s conversion.Scope) error {
|
||||
return autoConvert_admissionregistration_ValidatingAdmissionPolicyStatus_To_v1alpha1_ValidatingAdmissionPolicyStatus(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_Validation_To_admissionregistration_Validation(in *v1alpha1.Validation, out *admissionregistration.Validation, s conversion.Scope) error {
|
||||
out.Expression = in.Expression
|
||||
out.Message = in.Message
|
||||
|
@@ -33,6 +33,7 @@ import (
|
||||
celconfig "k8s.io/apiserver/pkg/apis/cel"
|
||||
"k8s.io/apiserver/pkg/cel"
|
||||
"k8s.io/apiserver/pkg/util/webhook"
|
||||
"k8s.io/client-go/util/jsonpath"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/admissionregistration"
|
||||
admissionregistrationv1 "k8s.io/kubernetes/pkg/apis/admissionregistration/v1"
|
||||
@@ -916,7 +917,56 @@ func ValidateValidatingAdmissionPolicyUpdate(newC, oldC *admissionregistration.V
|
||||
return validateValidatingAdmissionPolicy(newC)
|
||||
}
|
||||
|
||||
// ValidateValidatingAdmissionPolicyStatusUpdate validates update of status of validating admission policy
|
||||
func ValidateValidatingAdmissionPolicyStatusUpdate(newC, oldC *admissionregistration.ValidatingAdmissionPolicy) field.ErrorList {
|
||||
return validateValidatingAdmissionPolicyStatus(&newC.Status, field.NewPath("status"))
|
||||
}
|
||||
|
||||
// ValidateValidatingAdmissionPolicyBindingUpdate validates update of validating admission policy
|
||||
func ValidateValidatingAdmissionPolicyBindingUpdate(newC, oldC *admissionregistration.ValidatingAdmissionPolicyBinding) field.ErrorList {
|
||||
return validateValidatingAdmissionPolicyBinding(newC)
|
||||
}
|
||||
|
||||
func validateValidatingAdmissionPolicyStatus(status *admissionregistration.ValidatingAdmissionPolicyStatus, fldPath *field.Path) field.ErrorList {
|
||||
var allErrors field.ErrorList
|
||||
allErrors = append(allErrors, validateTypeChecking(status.TypeChecking, fldPath.Child("typeChecking"))...)
|
||||
allErrors = append(allErrors, metav1validation.ValidateConditions(status.Conditions, fldPath.Child("conditions"))...)
|
||||
return allErrors
|
||||
}
|
||||
|
||||
func validateTypeChecking(typeChecking *admissionregistration.TypeChecking, fldPath *field.Path) field.ErrorList {
|
||||
if typeChecking == nil {
|
||||
return nil
|
||||
}
|
||||
return validateExpressionWarnings(typeChecking.ExpressionWarnings, fldPath.Child("expressionWarnings"))
|
||||
}
|
||||
|
||||
func validateExpressionWarnings(expressionWarnings []admissionregistration.ExpressionWarning, fldPath *field.Path) field.ErrorList {
|
||||
var allErrors field.ErrorList
|
||||
for i, warning := range expressionWarnings {
|
||||
allErrors = append(allErrors, validateExpressionWarning(&warning, fldPath.Index(i))...)
|
||||
}
|
||||
return allErrors
|
||||
}
|
||||
|
||||
func validateExpressionWarning(expressionWarning *admissionregistration.ExpressionWarning, fldPath *field.Path) field.ErrorList {
|
||||
var allErrors field.ErrorList
|
||||
if expressionWarning.Warning == "" {
|
||||
allErrors = append(allErrors, field.Required(fldPath.Child("warning"), ""))
|
||||
}
|
||||
allErrors = append(allErrors, validateFieldRef(expressionWarning.FieldRef, fldPath.Child("fieldRef"))...)
|
||||
return allErrors
|
||||
}
|
||||
|
||||
func validateFieldRef(fieldRef string, fldPath *field.Path) field.ErrorList {
|
||||
fieldRef = strings.TrimSpace(fieldRef)
|
||||
if fieldRef == "" {
|
||||
return field.ErrorList{field.Required(fldPath, "")}
|
||||
}
|
||||
jsonPath := jsonpath.New("spec")
|
||||
if err := jsonPath.Parse(fmt.Sprintf("{%s}", fieldRef)); err != nil {
|
||||
return field.ErrorList{field.Invalid(fldPath, fieldRef, fmt.Sprintf("invalid JSONPath: %v", err))}
|
||||
}
|
||||
// no further checks, for an easier upgrade/rollback
|
||||
return nil
|
||||
}
|
||||
|
@@ -21,6 +21,7 @@ import (
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/admissionregistration"
|
||||
)
|
||||
@@ -3453,3 +3454,83 @@ func TestValidateValidatingAdmissionPolicyBindingUpdate(t *testing.T) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateValidatingAdmissionPolicyStatus(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
status *admissionregistration.ValidatingAdmissionPolicyStatus
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
status: &admissionregistration.ValidatingAdmissionPolicyStatus{},
|
||||
},
|
||||
{
|
||||
name: "type checking",
|
||||
status: &admissionregistration.ValidatingAdmissionPolicyStatus{
|
||||
TypeChecking: &admissionregistration.TypeChecking{
|
||||
ExpressionWarnings: []admissionregistration.ExpressionWarning{
|
||||
{
|
||||
FieldRef: "spec.validations[0].expression",
|
||||
Warning: "message",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "type checking bad json path",
|
||||
status: &admissionregistration.ValidatingAdmissionPolicyStatus{
|
||||
TypeChecking: &admissionregistration.TypeChecking{
|
||||
ExpressionWarnings: []admissionregistration.ExpressionWarning{
|
||||
{
|
||||
FieldRef: "spec[foo]",
|
||||
Warning: "message",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: "invalid JSONPath: invalid array index foo",
|
||||
},
|
||||
{
|
||||
name: "type checking missing warning",
|
||||
status: &admissionregistration.ValidatingAdmissionPolicyStatus{
|
||||
TypeChecking: &admissionregistration.TypeChecking{
|
||||
ExpressionWarnings: []admissionregistration.ExpressionWarning{
|
||||
{
|
||||
FieldRef: "spec.validations[0].expression",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: "Required value",
|
||||
},
|
||||
{
|
||||
name: "type checking missing fieldRef",
|
||||
status: &admissionregistration.ValidatingAdmissionPolicyStatus{
|
||||
TypeChecking: &admissionregistration.TypeChecking{
|
||||
ExpressionWarnings: []admissionregistration.ExpressionWarning{
|
||||
{
|
||||
Warning: "message",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: "Required value",
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
errs := validateValidatingAdmissionPolicyStatus(tc.status, field.NewPath("status"))
|
||||
err := errs.ToAggregate()
|
||||
if err != nil {
|
||||
if e, a := tc.expectedError, err.Error(); !strings.Contains(a, e) || e == "" {
|
||||
t.Errorf("expected to contain %s, got %s", e, a)
|
||||
}
|
||||
} else {
|
||||
if tc.expectedError != "" {
|
||||
t.Errorf("unexpected no error, expected to contain %s", tc.expectedError)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@@ -42,6 +42,22 @@ func (in *AuditAnnotation) DeepCopy() *AuditAnnotation {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ExpressionWarning) DeepCopyInto(out *ExpressionWarning) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExpressionWarning.
|
||||
func (in *ExpressionWarning) DeepCopy() *ExpressionWarning {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ExpressionWarning)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *MatchResources) DeepCopyInto(out *MatchResources) {
|
||||
*out = *in
|
||||
@@ -350,12 +366,34 @@ func (in *ServiceReference) DeepCopy() *ServiceReference {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TypeChecking) DeepCopyInto(out *TypeChecking) {
|
||||
*out = *in
|
||||
if in.ExpressionWarnings != nil {
|
||||
in, out := &in.ExpressionWarnings, &out.ExpressionWarnings
|
||||
*out = make([]ExpressionWarning, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TypeChecking.
|
||||
func (in *TypeChecking) DeepCopy() *TypeChecking {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(TypeChecking)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ValidatingAdmissionPolicy) DeepCopyInto(out *ValidatingAdmissionPolicy) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -544,6 +582,34 @@ func (in *ValidatingAdmissionPolicySpec) DeepCopy() *ValidatingAdmissionPolicySp
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ValidatingAdmissionPolicyStatus) DeepCopyInto(out *ValidatingAdmissionPolicyStatus) {
|
||||
*out = *in
|
||||
if in.TypeChecking != nil {
|
||||
in, out := &in.TypeChecking, &out.TypeChecking
|
||||
*out = new(TypeChecking)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]v1.Condition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ValidatingAdmissionPolicyStatus.
|
||||
func (in *ValidatingAdmissionPolicyStatus) DeepCopy() *ValidatingAdmissionPolicyStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ValidatingAdmissionPolicyStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ValidatingWebhook) DeepCopyInto(out *ValidatingWebhook) {
|
||||
*out = *in
|
||||
|
126
pkg/generated/openapi/zz_generated.openapi.go
generated
126
pkg/generated/openapi/zz_generated.openapi.go
generated
@@ -46,16 +46,19 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
|
||||
"k8s.io/api/admissionregistration/v1.ValidatingWebhookConfigurationList": schema_k8sio_api_admissionregistration_v1_ValidatingWebhookConfigurationList(ref),
|
||||
"k8s.io/api/admissionregistration/v1.WebhookClientConfig": schema_k8sio_api_admissionregistration_v1_WebhookClientConfig(ref),
|
||||
"k8s.io/api/admissionregistration/v1alpha1.AuditAnnotation": schema_k8sio_api_admissionregistration_v1alpha1_AuditAnnotation(ref),
|
||||
"k8s.io/api/admissionregistration/v1alpha1.ExpressionWarning": schema_k8sio_api_admissionregistration_v1alpha1_ExpressionWarning(ref),
|
||||
"k8s.io/api/admissionregistration/v1alpha1.MatchResources": schema_k8sio_api_admissionregistration_v1alpha1_MatchResources(ref),
|
||||
"k8s.io/api/admissionregistration/v1alpha1.NamedRuleWithOperations": schema_k8sio_api_admissionregistration_v1alpha1_NamedRuleWithOperations(ref),
|
||||
"k8s.io/api/admissionregistration/v1alpha1.ParamKind": schema_k8sio_api_admissionregistration_v1alpha1_ParamKind(ref),
|
||||
"k8s.io/api/admissionregistration/v1alpha1.ParamRef": schema_k8sio_api_admissionregistration_v1alpha1_ParamRef(ref),
|
||||
"k8s.io/api/admissionregistration/v1alpha1.TypeChecking": schema_k8sio_api_admissionregistration_v1alpha1_TypeChecking(ref),
|
||||
"k8s.io/api/admissionregistration/v1alpha1.ValidatingAdmissionPolicy": schema_k8sio_api_admissionregistration_v1alpha1_ValidatingAdmissionPolicy(ref),
|
||||
"k8s.io/api/admissionregistration/v1alpha1.ValidatingAdmissionPolicyBinding": schema_k8sio_api_admissionregistration_v1alpha1_ValidatingAdmissionPolicyBinding(ref),
|
||||
"k8s.io/api/admissionregistration/v1alpha1.ValidatingAdmissionPolicyBindingList": schema_k8sio_api_admissionregistration_v1alpha1_ValidatingAdmissionPolicyBindingList(ref),
|
||||
"k8s.io/api/admissionregistration/v1alpha1.ValidatingAdmissionPolicyBindingSpec": schema_k8sio_api_admissionregistration_v1alpha1_ValidatingAdmissionPolicyBindingSpec(ref),
|
||||
"k8s.io/api/admissionregistration/v1alpha1.ValidatingAdmissionPolicyList": schema_k8sio_api_admissionregistration_v1alpha1_ValidatingAdmissionPolicyList(ref),
|
||||
"k8s.io/api/admissionregistration/v1alpha1.ValidatingAdmissionPolicySpec": schema_k8sio_api_admissionregistration_v1alpha1_ValidatingAdmissionPolicySpec(ref),
|
||||
"k8s.io/api/admissionregistration/v1alpha1.ValidatingAdmissionPolicyStatus": schema_k8sio_api_admissionregistration_v1alpha1_ValidatingAdmissionPolicyStatus(ref),
|
||||
"k8s.io/api/admissionregistration/v1alpha1.Validation": schema_k8sio_api_admissionregistration_v1alpha1_Validation(ref),
|
||||
"k8s.io/api/admissionregistration/v1beta1.MutatingWebhook": schema_k8sio_api_admissionregistration_v1beta1_MutatingWebhook(ref),
|
||||
"k8s.io/api/admissionregistration/v1beta1.MutatingWebhookConfiguration": schema_k8sio_api_admissionregistration_v1beta1_MutatingWebhookConfiguration(ref),
|
||||
@@ -1889,6 +1892,36 @@ func schema_k8sio_api_admissionregistration_v1alpha1_AuditAnnotation(ref common.
|
||||
}
|
||||
}
|
||||
|
||||
func schema_k8sio_api_admissionregistration_v1alpha1_ExpressionWarning(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "ExpressionWarning is a warning information that targets a specific expression.",
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"fieldRef": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The path to the field that refers the expression. For example, the reference to the expression of the first item of validations is \"spec.validations[0].expression\"",
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"warning": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The content of type checking information in a human-readable form. Each line of the warning contains the type that the expression is checked against, followed by the type check error from the compiler.",
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"fieldRef", "warning"},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_k8sio_api_admissionregistration_v1alpha1_MatchResources(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
@@ -2156,6 +2189,40 @@ func schema_k8sio_api_admissionregistration_v1alpha1_ParamRef(ref common.Referen
|
||||
}
|
||||
}
|
||||
|
||||
func schema_k8sio_api_admissionregistration_v1alpha1_TypeChecking(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "TypeChecking contains results of type checking the expressions in the ValidatingAdmissionPolicy",
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"expressionWarnings": {
|
||||
VendorExtensible: spec.VendorExtensible{
|
||||
Extensions: spec.Extensions{
|
||||
"x-kubernetes-list-type": "atomic",
|
||||
},
|
||||
},
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The type checking warnings for each expression.",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("k8s.io/api/admissionregistration/v1alpha1.ExpressionWarning"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"k8s.io/api/admissionregistration/v1alpha1.ExpressionWarning"},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_k8sio_api_admissionregistration_v1alpha1_ValidatingAdmissionPolicy(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
@@ -2191,11 +2258,18 @@ func schema_k8sio_api_admissionregistration_v1alpha1_ValidatingAdmissionPolicy(r
|
||||
Ref: ref("k8s.io/api/admissionregistration/v1alpha1.ValidatingAdmissionPolicySpec"),
|
||||
},
|
||||
},
|
||||
"status": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The status of the ValidatingAdmissionPolicy, including warnings that are useful to determine if the policy behaves in the expected way. Populated by the system. Read-only.",
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("k8s.io/api/admissionregistration/v1alpha1.ValidatingAdmissionPolicyStatus"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"k8s.io/api/admissionregistration/v1alpha1.ValidatingAdmissionPolicySpec", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
"k8s.io/api/admissionregistration/v1alpha1.ValidatingAdmissionPolicySpec", "k8s.io/api/admissionregistration/v1alpha1.ValidatingAdmissionPolicyStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2469,6 +2543,56 @@ func schema_k8sio_api_admissionregistration_v1alpha1_ValidatingAdmissionPolicySp
|
||||
}
|
||||
}
|
||||
|
||||
func schema_k8sio_api_admissionregistration_v1alpha1_ValidatingAdmissionPolicyStatus(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "ValidatingAdmissionPolicyStatus represents the status of a ValidatingAdmissionPolicy.",
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"observedGeneration": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The generation observed by the controller.",
|
||||
Type: []string{"integer"},
|
||||
Format: "int64",
|
||||
},
|
||||
},
|
||||
"typeChecking": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The results of type checking for each expression. Presence of this field indicates the completion of the type checking.",
|
||||
Ref: ref("k8s.io/api/admissionregistration/v1alpha1.TypeChecking"),
|
||||
},
|
||||
},
|
||||
"conditions": {
|
||||
VendorExtensible: spec.VendorExtensible{
|
||||
Extensions: spec.Extensions{
|
||||
"x-kubernetes-list-map-keys": []interface{}{
|
||||
"type",
|
||||
},
|
||||
"x-kubernetes-list-type": "map",
|
||||
},
|
||||
},
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The conditions represent the latest available observations of a policy's current state.",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"k8s.io/api/admissionregistration/v1alpha1.TypeChecking", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_k8sio_api_admissionregistration_v1alpha1_Validation(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
|
@@ -28,6 +28,7 @@ import (
|
||||
utilwait "k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
webhookinit "k8s.io/apiserver/pkg/admission/plugin/webhook/initializer"
|
||||
"k8s.io/apiserver/pkg/cel/openapi/resolver"
|
||||
genericapiserver "k8s.io/apiserver/pkg/server"
|
||||
egressselector "k8s.io/apiserver/pkg/server/egressselector"
|
||||
"k8s.io/apiserver/pkg/util/webhook"
|
||||
@@ -47,7 +48,7 @@ type Config struct {
|
||||
}
|
||||
|
||||
// New sets up the plugins and admission start hooks needed for admission
|
||||
func (c *Config) New(proxyTransport *http.Transport, egressSelector *egressselector.EgressSelector, serviceResolver webhook.ServiceResolver, tp trace.TracerProvider) ([]admission.PluginInitializer, genericapiserver.PostStartHookFunc, error) {
|
||||
func (c *Config) New(proxyTransport *http.Transport, egressSelector *egressselector.EgressSelector, serviceResolver webhook.ServiceResolver, tp trace.TracerProvider, schemaResolver resolver.SchemaResolver) ([]admission.PluginInitializer, genericapiserver.PostStartHookFunc, error) {
|
||||
webhookAuthResolverWrapper := webhook.NewDefaultAuthenticationInfoResolverWrapper(proxyTransport, egressSelector, c.LoopbackClientConfig, tp)
|
||||
webhookPluginInitializer := webhookinit.NewPluginInitializer(webhookAuthResolverWrapper, serviceResolver)
|
||||
|
||||
@@ -63,13 +64,13 @@ func (c *Config) New(proxyTransport *http.Transport, egressSelector *egressselec
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
discoveryClient := cacheddiscovery.NewMemCacheClient(clientset.Discovery())
|
||||
discoveryRESTMapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient)
|
||||
kubePluginInitializer := NewPluginInitializer(
|
||||
cloudConfig,
|
||||
discoveryRESTMapper,
|
||||
quotainstall.NewQuotaConfigurationForAdmission(),
|
||||
schemaResolver,
|
||||
)
|
||||
|
||||
admissionPostStartHook := func(context genericapiserver.PostStartHookContext) error {
|
||||
|
@@ -20,6 +20,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
"k8s.io/apiserver/pkg/admission/initializer"
|
||||
"k8s.io/apiserver/pkg/cel/openapi/resolver"
|
||||
quota "k8s.io/apiserver/pkg/quota/v1"
|
||||
)
|
||||
|
||||
@@ -35,6 +36,7 @@ type PluginInitializer struct {
|
||||
cloudConfig []byte
|
||||
restMapper meta.RESTMapper
|
||||
quotaConfiguration quota.Configuration
|
||||
schemaResolver resolver.SchemaResolver
|
||||
}
|
||||
|
||||
var _ admission.PluginInitializer = &PluginInitializer{}
|
||||
@@ -46,11 +48,13 @@ func NewPluginInitializer(
|
||||
cloudConfig []byte,
|
||||
restMapper meta.RESTMapper,
|
||||
quotaConfiguration quota.Configuration,
|
||||
schemaResolver resolver.SchemaResolver,
|
||||
) *PluginInitializer {
|
||||
return &PluginInitializer{
|
||||
cloudConfig: cloudConfig,
|
||||
restMapper: restMapper,
|
||||
quotaConfiguration: quotaConfiguration,
|
||||
schemaResolver: schemaResolver,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,4 +72,8 @@ func (i *PluginInitializer) Initialize(plugin admission.Interface) {
|
||||
if wants, ok := plugin.(initializer.WantsQuotaConfiguration); ok {
|
||||
wants.SetQuotaConfiguration(i.quotaConfiguration)
|
||||
}
|
||||
|
||||
if wants, ok := plugin.(initializer.WantsSchemaResolver); ok {
|
||||
wants.SetSchemaResolver(i.schemaResolver)
|
||||
}
|
||||
}
|
||||
|
@@ -49,7 +49,7 @@ func (p *WantsCloudConfigAdmissionPlugin) SetCloudConfig(cloudConfig []byte) {
|
||||
|
||||
func TestCloudConfigAdmissionPlugin(t *testing.T) {
|
||||
cloudConfig := []byte("cloud-configuration")
|
||||
initializer := NewPluginInitializer(cloudConfig, nil, nil)
|
||||
initializer := NewPluginInitializer(cloudConfig, nil, nil, nil)
|
||||
wantsCloudConfigAdmission := &WantsCloudConfigAdmissionPlugin{}
|
||||
initializer.Initialize(wantsCloudConfigAdmission)
|
||||
|
||||
@@ -94,7 +94,7 @@ func (p *WantsRESTMapperAdmissionPlugin) SetRESTMapper(mapper meta.RESTMapper) {
|
||||
|
||||
func TestRESTMapperAdmissionPlugin(t *testing.T) {
|
||||
mapper := doNothingRESTMapper{}
|
||||
initializer := NewPluginInitializer(nil, mapper, nil)
|
||||
initializer := NewPluginInitializer(nil, mapper, nil, nil)
|
||||
wantsRESTMapperAdmission := &WantsRESTMapperAdmissionPlugin{}
|
||||
initializer.Initialize(wantsRESTMapperAdmission)
|
||||
|
||||
@@ -121,7 +121,7 @@ func (p *WantsQuotaConfigurationAdmissionPlugin) SetQuotaConfiguration(config qu
|
||||
|
||||
func TestQuotaConfigurationAdmissionPlugin(t *testing.T) {
|
||||
config := doNothingQuotaConfiguration{}
|
||||
initializer := NewPluginInitializer(nil, nil, config)
|
||||
initializer := NewPluginInitializer(nil, nil, config, nil)
|
||||
wantsQuotaConfigurationAdmission := &WantsQuotaConfigurationAdmissionPlugin{}
|
||||
initializer.Initialize(wantsQuotaConfigurationAdmission)
|
||||
|
||||
|
@@ -95,12 +95,13 @@ func (p RESTStorageProvider) v1alpha1Storage(apiResourceConfigSource serverstora
|
||||
|
||||
// validatingadmissionpolicies
|
||||
if resource := "validatingadmissionpolicies"; apiResourceConfigSource.ResourceEnabled(admissionregistrationv1alpha1.SchemeGroupVersion.WithResource(resource)) {
|
||||
policyStorage, err := validatingadmissionpolicystorage.NewREST(restOptionsGetter, p.Authorizer, r)
|
||||
policyStorage, policyStatusStorage, err := validatingadmissionpolicystorage.NewREST(restOptionsGetter, p.Authorizer, r)
|
||||
if err != nil {
|
||||
return storage, err
|
||||
}
|
||||
policyGetter = policyStorage
|
||||
storage[resource] = policyStorage
|
||||
storage[resource+"/status"] = policyStatusStorage
|
||||
}
|
||||
|
||||
// validatingadmissionpolicybindings
|
||||
|
@@ -17,6 +17,9 @@ limitations under the License.
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
"k8s.io/apiserver/pkg/registry/generic"
|
||||
@@ -28,6 +31,7 @@ import (
|
||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||
"k8s.io/kubernetes/pkg/registry/admissionregistration/resolver"
|
||||
"k8s.io/kubernetes/pkg/registry/admissionregistration/validatingadmissionpolicy"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
)
|
||||
|
||||
// REST implements a RESTStorage for validatingAdmissionPolicy against etcd
|
||||
@@ -35,10 +39,16 @@ type REST struct {
|
||||
*genericregistry.Store
|
||||
}
|
||||
|
||||
// StatusREST implements a RESTStorage for ValidatingAdmissionPolicyStatus
|
||||
type StatusREST struct {
|
||||
// DO NOT embed Store, manually select function to export.
|
||||
store *genericregistry.Store
|
||||
}
|
||||
|
||||
var groupResource = admissionregistration.Resource("validatingadmissionpolicies")
|
||||
|
||||
// NewREST returns a RESTStorage object that will work against validatingAdmissionPolicy.
|
||||
func NewREST(optsGetter generic.RESTOptionsGetter, authorizer authorizer.Authorizer, resourceResolver resolver.ResourceResolver) (*REST, error) {
|
||||
// NewREST returns two RESTStorage objects that will work against validatingAdmissionPolicy and its status.
|
||||
func NewREST(optsGetter generic.RESTOptionsGetter, authorizer authorizer.Authorizer, resourceResolver resolver.ResourceResolver) (*REST, *StatusREST, error) {
|
||||
r := &REST{}
|
||||
strategy := validatingadmissionpolicy.NewStrategy(authorizer, resourceResolver)
|
||||
store := &genericregistry.Store{
|
||||
@@ -50,18 +60,24 @@ func NewREST(optsGetter generic.RESTOptionsGetter, authorizer authorizer.Authori
|
||||
DefaultQualifiedResource: groupResource,
|
||||
SingularQualifiedResource: admissionregistration.Resource("validatingadmissionpolicy"),
|
||||
|
||||
CreateStrategy: strategy,
|
||||
UpdateStrategy: strategy,
|
||||
DeleteStrategy: strategy,
|
||||
CreateStrategy: strategy,
|
||||
UpdateStrategy: strategy,
|
||||
DeleteStrategy: strategy,
|
||||
ResetFieldsStrategy: strategy,
|
||||
|
||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||
}
|
||||
options := &generic.StoreOptions{RESTOptions: optsGetter}
|
||||
if err := store.CompleteWithOptions(options); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
r.Store = store
|
||||
return r, nil
|
||||
statusStrategy := validatingadmissionpolicy.NewStatusStrategy(strategy)
|
||||
statusStore := *store
|
||||
statusStore.UpdateStrategy = statusStrategy
|
||||
statusStore.ResetFieldsStrategy = statusStrategy
|
||||
sr := &StatusREST{store: &statusStore}
|
||||
return r, sr, nil
|
||||
}
|
||||
|
||||
// Implement CategoriesProvider
|
||||
@@ -71,3 +87,34 @@ var _ rest.CategoriesProvider = &REST{}
|
||||
func (r *REST) Categories() []string {
|
||||
return []string{"api-extensions"}
|
||||
}
|
||||
|
||||
// New generates a new ValidatingAdmissionPolicy object
|
||||
func (r *StatusREST) New() runtime.Object {
|
||||
return &admissionregistration.ValidatingAdmissionPolicy{}
|
||||
}
|
||||
|
||||
// Destroy disposes the store object. For the StatusREST, this is a no-op.
|
||||
func (r *StatusREST) Destroy() {
|
||||
// Given that underlying store is shared with REST,
|
||||
// we don't destroy it here explicitly.
|
||||
}
|
||||
|
||||
// Get retrieves the object from the storage. It is required to support Patch.
|
||||
func (r *StatusREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
|
||||
return r.store.Get(ctx, name, options)
|
||||
}
|
||||
|
||||
// GetResetFields returns the fields that got reset by the REST endpoint
|
||||
func (r *StatusREST) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||
return r.store.GetResetFields()
|
||||
}
|
||||
|
||||
// ConvertToTable delegates to the store, implements TableConverter
|
||||
func (r *StatusREST) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) {
|
||||
return r.store.ConvertToTable(ctx, object, tableOptions)
|
||||
}
|
||||
|
||||
// Update alters the status subset of an object. Delegates to the store
|
||||
func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) {
|
||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, forceAllowCreate, options)
|
||||
}
|
||||
|
@@ -211,7 +211,7 @@ func newStorage(t *testing.T, authorizer authorizer.Authorizer, resourceResolver
|
||||
Decorator: generic.UndecoratedStorage,
|
||||
DeleteCollectionWorkers: 1,
|
||||
ResourcePrefix: "validatingadmissionpolicies"}
|
||||
storage, err := NewREST(restOptions, authorizer, resourceResolver)
|
||||
storage, _, err := NewREST(restOptions, authorizer, resourceResolver)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error from REST storage: %v", err)
|
||||
}
|
||||
|
@@ -19,7 +19,10 @@ package validatingadmissionpolicy
|
||||
import (
|
||||
"context"
|
||||
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
@@ -56,6 +59,7 @@ func (v *validatingAdmissionPolicyStrategy) NamespaceScoped() bool {
|
||||
// PrepareForCreate clears the status of an validatingAdmissionPolicy before creation.
|
||||
func (v *validatingAdmissionPolicyStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||
ic := obj.(*admissionregistration.ValidatingAdmissionPolicy)
|
||||
ic.Status = admissionregistration.ValidatingAdmissionPolicyStatus{}
|
||||
ic.Generation = 1
|
||||
}
|
||||
|
||||
@@ -64,6 +68,9 @@ func (v *validatingAdmissionPolicyStrategy) PrepareForUpdate(ctx context.Context
|
||||
newIC := obj.(*admissionregistration.ValidatingAdmissionPolicy)
|
||||
oldIC := old.(*admissionregistration.ValidatingAdmissionPolicy)
|
||||
|
||||
// Prevent any update on the Status object
|
||||
newIC.Status = oldIC.Status
|
||||
|
||||
// Any changes to the spec increment the generation number, any changes to the
|
||||
// status should reflect the generation number of the corresponding object.
|
||||
// See metav1.ObjectMeta description for more information on Generation.
|
||||
@@ -120,3 +127,53 @@ func (v *validatingAdmissionPolicyStrategy) WarningsOnUpdate(ctx context.Context
|
||||
func (v *validatingAdmissionPolicyStrategy) AllowUnconditionalUpdate() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// GetResetFields returns the set of fields that get reset by the strategy
|
||||
// and should not be modified by the user.
|
||||
func (v *validatingAdmissionPolicyStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||
"admissionregistration.k8s.io/v1alpha1": fieldpath.NewSet(
|
||||
fieldpath.MakePathOrDie("status"),
|
||||
),
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
type validatingAdmissionPolicyStatusStrategy struct {
|
||||
*validatingAdmissionPolicyStrategy
|
||||
}
|
||||
|
||||
// ValidateUpdate is the default update validation of an update to the status object.
|
||||
func (s *validatingAdmissionPolicyStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
|
||||
return validation.ValidateValidatingAdmissionPolicyStatusUpdate(obj.(*admissionregistration.ValidatingAdmissionPolicy), old.(*admissionregistration.ValidatingAdmissionPolicy))
|
||||
}
|
||||
|
||||
// PrepareForUpdate differs from the main strategy where setting the spec is not
|
||||
// allowed, but setting status is OK.
|
||||
func (s *validatingAdmissionPolicyStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||
newIC := obj.(*admissionregistration.ValidatingAdmissionPolicy)
|
||||
oldIC := old.(*admissionregistration.ValidatingAdmissionPolicy)
|
||||
|
||||
// Prevent any update on the Spec object from Status Strategy
|
||||
newIC.Spec = oldIC.Spec
|
||||
|
||||
metav1.ResetObjectMetaForStatus(&newIC.ObjectMeta, &oldIC.ObjectMeta)
|
||||
// No change in the generation.
|
||||
}
|
||||
|
||||
// GetResetFields returns the set of fields that get reset by the strategy
|
||||
// and should not be modified by the user.
|
||||
func (s *validatingAdmissionPolicyStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||
return map[fieldpath.APIVersion]*fieldpath.Set{
|
||||
"admissionregistration.k8s.io/v1alpha1": fieldpath.NewSet(
|
||||
fieldpath.MakePathOrDie("spec"),
|
||||
fieldpath.MakePathOrDie("metadata"),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// NewStatusStrategy creates a strategy for operating the status object.
|
||||
func NewStatusStrategy(policyStrategy *validatingAdmissionPolicyStrategy) *validatingAdmissionPolicyStatusStrategy {
|
||||
return &validatingAdmissionPolicyStatusStrategy{validatingAdmissionPolicyStrategy: policyStrategy}
|
||||
}
|
||||
|
Reference in New Issue
Block a user