Merge pull request #115668 from jiahuif-forks/feature/validating-admission-policy/type-system
Type System for ValidatingAdmissionPolicy
This commit is contained in:
commit
152876a3eb
270
api/openapi-spec/swagger.json
generated
270
api/openapi-spec/swagger.json
generated
@ -366,6 +366,24 @@
|
|||||||
],
|
],
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
"io.k8s.api.admissionregistration.v1alpha1.ExpressionWarning": {
|
||||||
|
"description": "ExpressionWarning is a warning information that targets a specific expression.",
|
||||||
|
"properties": {
|
||||||
|
"fieldRef": {
|
||||||
|
"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\"",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"warning": {
|
||||||
|
"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.",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"fieldRef",
|
||||||
|
"warning"
|
||||||
|
],
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
"io.k8s.api.admissionregistration.v1alpha1.MatchResources": {
|
"io.k8s.api.admissionregistration.v1alpha1.MatchResources": {
|
||||||
"description": "MatchResources decides whether to run the admission control policy on an object based on whether it meets the match criteria. The exclude rules take precedence over include rules (if a resource matches both, it is excluded)",
|
"description": "MatchResources decides whether to run the admission control policy on an object based on whether it meets the match criteria. The exclude rules take precedence over include rules (if a resource matches both, it is excluded)",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -482,6 +500,20 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"x-kubernetes-map-type": "atomic"
|
"x-kubernetes-map-type": "atomic"
|
||||||
},
|
},
|
||||||
|
"io.k8s.api.admissionregistration.v1alpha1.TypeChecking": {
|
||||||
|
"description": "TypeChecking contains results of type checking the expressions in the ValidatingAdmissionPolicy",
|
||||||
|
"properties": {
|
||||||
|
"expressionWarnings": {
|
||||||
|
"description": "The type checking warnings for each expression.",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/io.k8s.api.admissionregistration.v1alpha1.ExpressionWarning"
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
"x-kubernetes-list-type": "atomic"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
"io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy": {
|
"io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy": {
|
||||||
"description": "ValidatingAdmissionPolicy describes the definition of an admission validation policy that accepts or rejects an object without changing it.",
|
"description": "ValidatingAdmissionPolicy describes the definition of an admission validation policy that accepts or rejects an object without changing it.",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -500,6 +532,10 @@
|
|||||||
"spec": {
|
"spec": {
|
||||||
"$ref": "#/definitions/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicySpec",
|
"$ref": "#/definitions/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicySpec",
|
||||||
"description": "Specification of the desired behavior of the ValidatingAdmissionPolicy."
|
"description": "Specification of the desired behavior of the ValidatingAdmissionPolicy."
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"$ref": "#/definitions/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyStatus",
|
||||||
|
"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."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@ -664,6 +700,32 @@
|
|||||||
},
|
},
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
"io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyStatus": {
|
||||||
|
"description": "ValidatingAdmissionPolicyStatus represents the status of a ValidatingAdmissionPolicy.",
|
||||||
|
"properties": {
|
||||||
|
"conditions": {
|
||||||
|
"description": "The conditions represent the latest available observations of a policy's current state.",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Condition"
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
"x-kubernetes-list-map-keys": [
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"x-kubernetes-list-type": "map"
|
||||||
|
},
|
||||||
|
"observedGeneration": {
|
||||||
|
"description": "The generation observed by the controller.",
|
||||||
|
"format": "int64",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"typeChecking": {
|
||||||
|
"$ref": "#/definitions/io.k8s.api.admissionregistration.v1alpha1.TypeChecking",
|
||||||
|
"description": "The results of type checking for each expression. Presence of this field indicates the completion of the type checking."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
"io.k8s.api.admissionregistration.v1alpha1.Validation": {
|
"io.k8s.api.admissionregistration.v1alpha1.Validation": {
|
||||||
"description": "Validation specifies the CEL expression which is used to apply the validation.",
|
"description": "Validation specifies the CEL expression which is used to apply the validation.",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -39694,6 +39756,214 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/apis/admissionregistration.k8s.io/v1alpha1/validatingadmissionpolicies/{name}/status": {
|
||||||
|
"get": {
|
||||||
|
"consumes": [
|
||||||
|
"*/*"
|
||||||
|
],
|
||||||
|
"description": "read status of the specified ValidatingAdmissionPolicy",
|
||||||
|
"operationId": "readAdmissionregistrationV1alpha1ValidatingAdmissionPolicyStatus",
|
||||||
|
"produces": [
|
||||||
|
"application/json",
|
||||||
|
"application/yaml",
|
||||||
|
"application/vnd.kubernetes.protobuf"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schemes": [
|
||||||
|
"https"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"admissionregistration_v1alpha1"
|
||||||
|
],
|
||||||
|
"x-kubernetes-action": "get",
|
||||||
|
"x-kubernetes-group-version-kind": {
|
||||||
|
"group": "admissionregistration.k8s.io",
|
||||||
|
"kind": "ValidatingAdmissionPolicy",
|
||||||
|
"version": "v1alpha1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "name of the ValidatingAdmissionPolicy",
|
||||||
|
"in": "path",
|
||||||
|
"name": "name",
|
||||||
|
"required": true,
|
||||||
|
"type": "string",
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "If 'true', then the output is pretty printed.",
|
||||||
|
"in": "query",
|
||||||
|
"name": "pretty",
|
||||||
|
"type": "string",
|
||||||
|
"uniqueItems": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"patch": {
|
||||||
|
"consumes": [
|
||||||
|
"application/json-patch+json",
|
||||||
|
"application/merge-patch+json",
|
||||||
|
"application/strategic-merge-patch+json",
|
||||||
|
"application/apply-patch+yaml"
|
||||||
|
],
|
||||||
|
"description": "partially update status of the specified ValidatingAdmissionPolicy",
|
||||||
|
"operationId": "patchAdmissionregistrationV1alpha1ValidatingAdmissionPolicyStatus",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "body",
|
||||||
|
"name": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Patch"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed",
|
||||||
|
"in": "query",
|
||||||
|
"name": "dryRun",
|
||||||
|
"type": "string",
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch).",
|
||||||
|
"in": "query",
|
||||||
|
"name": "fieldManager",
|
||||||
|
"type": "string",
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered.",
|
||||||
|
"in": "query",
|
||||||
|
"name": "fieldValidation",
|
||||||
|
"type": "string",
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Force is going to \"force\" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests.",
|
||||||
|
"in": "query",
|
||||||
|
"name": "force",
|
||||||
|
"type": "boolean",
|
||||||
|
"uniqueItems": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json",
|
||||||
|
"application/yaml",
|
||||||
|
"application/vnd.kubernetes.protobuf"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"201": {
|
||||||
|
"description": "Created",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schemes": [
|
||||||
|
"https"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"admissionregistration_v1alpha1"
|
||||||
|
],
|
||||||
|
"x-kubernetes-action": "patch",
|
||||||
|
"x-kubernetes-group-version-kind": {
|
||||||
|
"group": "admissionregistration.k8s.io",
|
||||||
|
"kind": "ValidatingAdmissionPolicy",
|
||||||
|
"version": "v1alpha1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"put": {
|
||||||
|
"consumes": [
|
||||||
|
"*/*"
|
||||||
|
],
|
||||||
|
"description": "replace status of the specified ValidatingAdmissionPolicy",
|
||||||
|
"operationId": "replaceAdmissionregistrationV1alpha1ValidatingAdmissionPolicyStatus",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "body",
|
||||||
|
"name": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed",
|
||||||
|
"in": "query",
|
||||||
|
"name": "dryRun",
|
||||||
|
"type": "string",
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint.",
|
||||||
|
"in": "query",
|
||||||
|
"name": "fieldManager",
|
||||||
|
"type": "string",
|
||||||
|
"uniqueItems": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered.",
|
||||||
|
"in": "query",
|
||||||
|
"name": "fieldValidation",
|
||||||
|
"type": "string",
|
||||||
|
"uniqueItems": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json",
|
||||||
|
"application/yaml",
|
||||||
|
"application/vnd.kubernetes.protobuf"
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"201": {
|
||||||
|
"description": "Created",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schemes": [
|
||||||
|
"https"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"admissionregistration_v1alpha1"
|
||||||
|
],
|
||||||
|
"x-kubernetes-action": "put",
|
||||||
|
"x-kubernetes-group-version-kind": {
|
||||||
|
"group": "admissionregistration.k8s.io",
|
||||||
|
"kind": "ValidatingAdmissionPolicy",
|
||||||
|
"version": "v1alpha1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/apis/admissionregistration.k8s.io/v1alpha1/validatingadmissionpolicybindings": {
|
"/apis/admissionregistration.k8s.io/v1alpha1/validatingadmissionpolicybindings": {
|
||||||
"delete": {
|
"delete": {
|
||||||
"consumes": [
|
"consumes": [
|
||||||
|
@ -21,6 +21,26 @@
|
|||||||
],
|
],
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
"io.k8s.api.admissionregistration.v1alpha1.ExpressionWarning": {
|
||||||
|
"description": "ExpressionWarning is a warning information that targets a specific expression.",
|
||||||
|
"properties": {
|
||||||
|
"fieldRef": {
|
||||||
|
"default": "",
|
||||||
|
"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\"",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"warning": {
|
||||||
|
"default": "",
|
||||||
|
"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.",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"fieldRef",
|
||||||
|
"warning"
|
||||||
|
],
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
"io.k8s.api.admissionregistration.v1alpha1.MatchResources": {
|
"io.k8s.api.admissionregistration.v1alpha1.MatchResources": {
|
||||||
"description": "MatchResources decides whether to run the admission control policy on an object based on whether it meets the match criteria. The exclude rules take precedence over include rules (if a resource matches both, it is excluded)",
|
"description": "MatchResources decides whether to run the admission control policy on an object based on whether it meets the match criteria. The exclude rules take precedence over include rules (if a resource matches both, it is excluded)",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -160,6 +180,25 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"x-kubernetes-map-type": "atomic"
|
"x-kubernetes-map-type": "atomic"
|
||||||
},
|
},
|
||||||
|
"io.k8s.api.admissionregistration.v1alpha1.TypeChecking": {
|
||||||
|
"description": "TypeChecking contains results of type checking the expressions in the ValidatingAdmissionPolicy",
|
||||||
|
"properties": {
|
||||||
|
"expressionWarnings": {
|
||||||
|
"description": "The type checking warnings for each expression.",
|
||||||
|
"items": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/io.k8s.api.admissionregistration.v1alpha1.ExpressionWarning"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"default": {}
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
"x-kubernetes-list-type": "atomic"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
"io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy": {
|
"io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy": {
|
||||||
"description": "ValidatingAdmissionPolicy describes the definition of an admission validation policy that accepts or rejects an object without changing it.",
|
"description": "ValidatingAdmissionPolicy describes the definition of an admission validation policy that accepts or rejects an object without changing it.",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -188,6 +227,15 @@
|
|||||||
],
|
],
|
||||||
"default": {},
|
"default": {},
|
||||||
"description": "Specification of the desired behavior of the ValidatingAdmissionPolicy."
|
"description": "Specification of the desired behavior of the ValidatingAdmissionPolicy."
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyStatus"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"default": {},
|
||||||
|
"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."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@ -409,6 +457,41 @@
|
|||||||
},
|
},
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
"io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyStatus": {
|
||||||
|
"description": "ValidatingAdmissionPolicyStatus represents the status of a ValidatingAdmissionPolicy.",
|
||||||
|
"properties": {
|
||||||
|
"conditions": {
|
||||||
|
"description": "The conditions represent the latest available observations of a policy's current state.",
|
||||||
|
"items": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/io.k8s.apimachinery.pkg.apis.meta.v1.Condition"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"default": {}
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
"x-kubernetes-list-map-keys": [
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"x-kubernetes-list-type": "map"
|
||||||
|
},
|
||||||
|
"observedGeneration": {
|
||||||
|
"description": "The generation observed by the controller.",
|
||||||
|
"format": "int64",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"typeChecking": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/io.k8s.api.admissionregistration.v1alpha1.TypeChecking"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "The results of type checking for each expression. Presence of this field indicates the completion of the type checking."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
"io.k8s.api.admissionregistration.v1alpha1.Validation": {
|
"io.k8s.api.admissionregistration.v1alpha1.Validation": {
|
||||||
"description": "Validation specifies the CEL expression which is used to apply the validation.",
|
"description": "Validation specifies the CEL expression which is used to apply the validation.",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -546,6 +629,53 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"io.k8s.apimachinery.pkg.apis.meta.v1.Condition": {
|
||||||
|
"description": "Condition contains details for one aspect of the current state of this API Resource.",
|
||||||
|
"properties": {
|
||||||
|
"lastTransitionTime": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/io.k8s.apimachinery.pkg.apis.meta.v1.Time"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"default": {},
|
||||||
|
"description": "lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable."
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"default": "",
|
||||||
|
"description": "message is a human readable message indicating details about the transition. This may be an empty string.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"observedGeneration": {
|
||||||
|
"description": "observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance.",
|
||||||
|
"format": "int64",
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"reason": {
|
||||||
|
"default": "",
|
||||||
|
"description": "reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"default": "",
|
||||||
|
"description": "status of the condition, one of True, False, Unknown.",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"default": "",
|
||||||
|
"description": "type of condition in CamelCase or in foo.example.com/CamelCase.",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"type",
|
||||||
|
"status",
|
||||||
|
"lastTransitionTime",
|
||||||
|
"reason",
|
||||||
|
"message"
|
||||||
|
],
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
"io.k8s.apimachinery.pkg.apis.meta.v1.DeleteOptions": {
|
"io.k8s.apimachinery.pkg.apis.meta.v1.DeleteOptions": {
|
||||||
"description": "DeleteOptions may be provided when deleting an API object.",
|
"description": "DeleteOptions may be provided when deleting an API object.",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -2463,6 +2593,283 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/apis/admissionregistration.k8s.io/v1alpha1/validatingadmissionpolicies/{name}/status": {
|
||||||
|
"get": {
|
||||||
|
"description": "read status of the specified ValidatingAdmissionPolicy",
|
||||||
|
"operationId": "readAdmissionregistrationV1alpha1ValidatingAdmissionPolicyStatus",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"application/vnd.kubernetes.protobuf": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"application/yaml": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "OK"
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"admissionregistration_v1alpha1"
|
||||||
|
],
|
||||||
|
"x-kubernetes-action": "get",
|
||||||
|
"x-kubernetes-group-version-kind": {
|
||||||
|
"group": "admissionregistration.k8s.io",
|
||||||
|
"kind": "ValidatingAdmissionPolicy",
|
||||||
|
"version": "v1alpha1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "name of the ValidatingAdmissionPolicy",
|
||||||
|
"in": "path",
|
||||||
|
"name": "name",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"uniqueItems": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "If 'true', then the output is pretty printed.",
|
||||||
|
"in": "query",
|
||||||
|
"name": "pretty",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"uniqueItems": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"patch": {
|
||||||
|
"description": "partially update status of the specified ValidatingAdmissionPolicy",
|
||||||
|
"operationId": "patchAdmissionregistrationV1alpha1ValidatingAdmissionPolicyStatus",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed",
|
||||||
|
"in": "query",
|
||||||
|
"name": "dryRun",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"uniqueItems": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch).",
|
||||||
|
"in": "query",
|
||||||
|
"name": "fieldManager",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"uniqueItems": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered.",
|
||||||
|
"in": "query",
|
||||||
|
"name": "fieldValidation",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"uniqueItems": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Force is going to \"force\" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests.",
|
||||||
|
"in": "query",
|
||||||
|
"name": "force",
|
||||||
|
"schema": {
|
||||||
|
"type": "boolean",
|
||||||
|
"uniqueItems": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/apply-patch+yaml": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/io.k8s.apimachinery.pkg.apis.meta.v1.Patch"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"application/json-patch+json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/io.k8s.apimachinery.pkg.apis.meta.v1.Patch"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"application/merge-patch+json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/io.k8s.apimachinery.pkg.apis.meta.v1.Patch"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"application/strategic-merge-patch+json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/io.k8s.apimachinery.pkg.apis.meta.v1.Patch"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"application/vnd.kubernetes.protobuf": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"application/yaml": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "OK"
|
||||||
|
},
|
||||||
|
"201": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"application/vnd.kubernetes.protobuf": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"application/yaml": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Created"
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"admissionregistration_v1alpha1"
|
||||||
|
],
|
||||||
|
"x-kubernetes-action": "patch",
|
||||||
|
"x-kubernetes-group-version-kind": {
|
||||||
|
"group": "admissionregistration.k8s.io",
|
||||||
|
"kind": "ValidatingAdmissionPolicy",
|
||||||
|
"version": "v1alpha1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"put": {
|
||||||
|
"description": "replace status of the specified ValidatingAdmissionPolicy",
|
||||||
|
"operationId": "replaceAdmissionregistrationV1alpha1ValidatingAdmissionPolicyStatus",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed",
|
||||||
|
"in": "query",
|
||||||
|
"name": "dryRun",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"uniqueItems": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint.",
|
||||||
|
"in": "query",
|
||||||
|
"name": "fieldManager",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"uniqueItems": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered.",
|
||||||
|
"in": "query",
|
||||||
|
"name": "fieldValidation",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"uniqueItems": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"*/*": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"application/vnd.kubernetes.protobuf": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"application/yaml": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "OK"
|
||||||
|
},
|
||||||
|
"201": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"application/vnd.kubernetes.protobuf": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"application/yaml": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Created"
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
"admissionregistration_v1alpha1"
|
||||||
|
],
|
||||||
|
"x-kubernetes-action": "put",
|
||||||
|
"x-kubernetes-group-version-kind": {
|
||||||
|
"group": "admissionregistration.k8s.io",
|
||||||
|
"kind": "ValidatingAdmissionPolicy",
|
||||||
|
"version": "v1alpha1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/apis/admissionregistration.k8s.io/v1alpha1/validatingadmissionpolicybindings": {
|
"/apis/admissionregistration.k8s.io/v1alpha1/validatingadmissionpolicybindings": {
|
||||||
"delete": {
|
"delete": {
|
||||||
"description": "delete collection of ValidatingAdmissionPolicyBinding",
|
"description": "delete collection of ValidatingAdmissionPolicyBinding",
|
||||||
|
@ -40,6 +40,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/apiserver/pkg/admission"
|
"k8s.io/apiserver/pkg/admission"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
|
"k8s.io/apiserver/pkg/cel/openapi/resolver"
|
||||||
"k8s.io/apiserver/pkg/endpoints/discovery/aggregated"
|
"k8s.io/apiserver/pkg/endpoints/discovery/aggregated"
|
||||||
genericapifilters "k8s.io/apiserver/pkg/endpoints/filters"
|
genericapifilters "k8s.io/apiserver/pkg/endpoints/filters"
|
||||||
openapinamer "k8s.io/apiserver/pkg/endpoints/openapi"
|
openapinamer "k8s.io/apiserver/pkg/endpoints/openapi"
|
||||||
@ -56,6 +57,7 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/util/webhook"
|
"k8s.io/apiserver/pkg/util/webhook"
|
||||||
clientgoinformers "k8s.io/client-go/informers"
|
clientgoinformers "k8s.io/client-go/informers"
|
||||||
clientgoclientset "k8s.io/client-go/kubernetes"
|
clientgoclientset "k8s.io/client-go/kubernetes"
|
||||||
|
k8sscheme "k8s.io/client-go/kubernetes/scheme"
|
||||||
"k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
"k8s.io/client-go/util/keyutil"
|
"k8s.io/client-go/util/keyutil"
|
||||||
cliflag "k8s.io/component-base/cli/flag"
|
cliflag "k8s.io/component-base/cli/flag"
|
||||||
@ -452,7 +454,8 @@ func buildGenericConfig(
|
|||||||
CloudConfigFile: s.CloudProvider.CloudConfigFile,
|
CloudConfigFile: s.CloudProvider.CloudConfigFile,
|
||||||
}
|
}
|
||||||
serviceResolver = buildServiceResolver(s.EnableAggregatorRouting, genericConfig.LoopbackClientConfig.Host, versionedInformers)
|
serviceResolver = buildServiceResolver(s.EnableAggregatorRouting, genericConfig.LoopbackClientConfig.Host, versionedInformers)
|
||||||
pluginInitializers, admissionPostStartHook, err = admissionConfig.New(proxyTransport, genericConfig.EgressSelector, serviceResolver, genericConfig.TracerProvider)
|
schemaResolver := resolver.NewDefinitionsSchemaResolver(k8sscheme.Scheme, genericConfig.OpenAPIConfig.GetDefinitions)
|
||||||
|
pluginInitializers, admissionPostStartHook, err = admissionConfig.New(proxyTransport, genericConfig.EgressSelector, serviceResolver, genericConfig.TracerProvider, schemaResolver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lastErr = fmt.Errorf("failed to create admission plugin initializer: %v", err)
|
lastErr = fmt.Errorf("failed to create admission plugin initializer: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -123,6 +123,52 @@ type ValidatingAdmissionPolicy struct {
|
|||||||
metav1.ObjectMeta
|
metav1.ObjectMeta
|
||||||
// Specification of the desired behavior of the ValidatingAdmissionPolicy.
|
// Specification of the desired behavior of the ValidatingAdmissionPolicy.
|
||||||
Spec ValidatingAdmissionPolicySpec
|
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
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
|
@ -49,6 +49,16 @@ func RegisterConversions(s *runtime.Scheme) error {
|
|||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
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 {
|
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)
|
return Convert_v1alpha1_MatchResources_To_admissionregistration_MatchResources(a.(*v1alpha1.MatchResources), b.(*admissionregistration.MatchResources), scope)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
@ -89,6 +99,16 @@ func RegisterConversions(s *runtime.Scheme) error {
|
|||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
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 {
|
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)
|
return Convert_v1alpha1_ValidatingAdmissionPolicy_To_admissionregistration_ValidatingAdmissionPolicy(a.(*v1alpha1.ValidatingAdmissionPolicy), b.(*admissionregistration.ValidatingAdmissionPolicy), scope)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
@ -149,6 +169,16 @@ func RegisterConversions(s *runtime.Scheme) error {
|
|||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
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 {
|
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)
|
return Convert_v1alpha1_Validation_To_admissionregistration_Validation(a.(*v1alpha1.Validation), b.(*admissionregistration.Validation), scope)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
@ -184,6 +214,28 @@ func Convert_admissionregistration_AuditAnnotation_To_v1alpha1_AuditAnnotation(i
|
|||||||
return autoConvert_admissionregistration_AuditAnnotation_To_v1alpha1_AuditAnnotation(in, out, s)
|
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 {
|
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.NamespaceSelector = (*v1.LabelSelector)(unsafe.Pointer(in.NamespaceSelector))
|
||||||
out.ObjectSelector = (*v1.LabelSelector)(unsafe.Pointer(in.ObjectSelector))
|
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)
|
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 {
|
func autoConvert_v1alpha1_ValidatingAdmissionPolicy_To_admissionregistration_ValidatingAdmissionPolicy(in *v1alpha1.ValidatingAdmissionPolicy, out *admissionregistration.ValidatingAdmissionPolicy, s conversion.Scope) error {
|
||||||
out.ObjectMeta = in.ObjectMeta
|
out.ObjectMeta = in.ObjectMeta
|
||||||
if err := Convert_v1alpha1_ValidatingAdmissionPolicySpec_To_admissionregistration_ValidatingAdmissionPolicySpec(&in.Spec, &out.Spec, s); err != nil {
|
if err := Convert_v1alpha1_ValidatingAdmissionPolicySpec_To_admissionregistration_ValidatingAdmissionPolicySpec(&in.Spec, &out.Spec, s); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := Convert_v1alpha1_ValidatingAdmissionPolicyStatus_To_admissionregistration_ValidatingAdmissionPolicyStatus(&in.Status, &out.Status, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
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 {
|
if err := Convert_admissionregistration_ValidatingAdmissionPolicySpec_To_v1alpha1_ValidatingAdmissionPolicySpec(&in.Spec, &out.Spec, s); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := Convert_admissionregistration_ValidatingAdmissionPolicyStatus_To_v1alpha1_ValidatingAdmissionPolicyStatus(&in.Status, &out.Status, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -544,6 +622,30 @@ func Convert_admissionregistration_ValidatingAdmissionPolicySpec_To_v1alpha1_Val
|
|||||||
return autoConvert_admissionregistration_ValidatingAdmissionPolicySpec_To_v1alpha1_ValidatingAdmissionPolicySpec(in, out, s)
|
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 {
|
func autoConvert_v1alpha1_Validation_To_admissionregistration_Validation(in *v1alpha1.Validation, out *admissionregistration.Validation, s conversion.Scope) error {
|
||||||
out.Expression = in.Expression
|
out.Expression = in.Expression
|
||||||
out.Message = in.Message
|
out.Message = in.Message
|
||||||
|
@ -33,6 +33,7 @@ import (
|
|||||||
celconfig "k8s.io/apiserver/pkg/apis/cel"
|
celconfig "k8s.io/apiserver/pkg/apis/cel"
|
||||||
"k8s.io/apiserver/pkg/cel"
|
"k8s.io/apiserver/pkg/cel"
|
||||||
"k8s.io/apiserver/pkg/util/webhook"
|
"k8s.io/apiserver/pkg/util/webhook"
|
||||||
|
"k8s.io/client-go/util/jsonpath"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/apis/admissionregistration"
|
"k8s.io/kubernetes/pkg/apis/admissionregistration"
|
||||||
admissionregistrationv1 "k8s.io/kubernetes/pkg/apis/admissionregistration/v1"
|
admissionregistrationv1 "k8s.io/kubernetes/pkg/apis/admissionregistration/v1"
|
||||||
@ -916,7 +917,56 @@ func ValidateValidatingAdmissionPolicyUpdate(newC, oldC *admissionregistration.V
|
|||||||
return validateValidatingAdmissionPolicy(newC)
|
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
|
// ValidateValidatingAdmissionPolicyBindingUpdate validates update of validating admission policy
|
||||||
func ValidateValidatingAdmissionPolicyBindingUpdate(newC, oldC *admissionregistration.ValidatingAdmissionPolicyBinding) field.ErrorList {
|
func ValidateValidatingAdmissionPolicyBindingUpdate(newC, oldC *admissionregistration.ValidatingAdmissionPolicyBinding) field.ErrorList {
|
||||||
return validateValidatingAdmissionPolicyBinding(newC)
|
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"
|
"testing"
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/apis/admissionregistration"
|
"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
|
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.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *MatchResources) DeepCopyInto(out *MatchResources) {
|
func (in *MatchResources) DeepCopyInto(out *MatchResources) {
|
||||||
*out = *in
|
*out = *in
|
||||||
@ -350,12 +366,34 @@ func (in *ServiceReference) DeepCopy() *ServiceReference {
|
|||||||
return out
|
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.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *ValidatingAdmissionPolicy) DeepCopyInto(out *ValidatingAdmissionPolicy) {
|
func (in *ValidatingAdmissionPolicy) DeepCopyInto(out *ValidatingAdmissionPolicy) {
|
||||||
*out = *in
|
*out = *in
|
||||||
out.TypeMeta = in.TypeMeta
|
out.TypeMeta = in.TypeMeta
|
||||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
in.Spec.DeepCopyInto(&out.Spec)
|
in.Spec.DeepCopyInto(&out.Spec)
|
||||||
|
in.Status.DeepCopyInto(&out.Status)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -544,6 +582,34 @@ func (in *ValidatingAdmissionPolicySpec) DeepCopy() *ValidatingAdmissionPolicySp
|
|||||||
return out
|
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.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *ValidatingWebhook) DeepCopyInto(out *ValidatingWebhook) {
|
func (in *ValidatingWebhook) DeepCopyInto(out *ValidatingWebhook) {
|
||||||
*out = *in
|
*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.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/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.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.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.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.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.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.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.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.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.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.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.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/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.MutatingWebhook": schema_k8sio_api_admissionregistration_v1beta1_MutatingWebhook(ref),
|
||||||
"k8s.io/api/admissionregistration/v1beta1.MutatingWebhookConfiguration": schema_k8sio_api_admissionregistration_v1beta1_MutatingWebhookConfiguration(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 {
|
func schema_k8sio_api_admissionregistration_v1alpha1_MatchResources(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||||
return common.OpenAPIDefinition{
|
return common.OpenAPIDefinition{
|
||||||
Schema: spec.Schema{
|
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 {
|
func schema_k8sio_api_admissionregistration_v1alpha1_ValidatingAdmissionPolicy(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||||
return common.OpenAPIDefinition{
|
return common.OpenAPIDefinition{
|
||||||
Schema: spec.Schema{
|
Schema: spec.Schema{
|
||||||
@ -2191,11 +2258,18 @@ func schema_k8sio_api_admissionregistration_v1alpha1_ValidatingAdmissionPolicy(r
|
|||||||
Ref: ref("k8s.io/api/admissionregistration/v1alpha1.ValidatingAdmissionPolicySpec"),
|
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{
|
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 {
|
func schema_k8sio_api_admissionregistration_v1alpha1_Validation(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||||
return common.OpenAPIDefinition{
|
return common.OpenAPIDefinition{
|
||||||
Schema: spec.Schema{
|
Schema: spec.Schema{
|
||||||
|
@ -28,6 +28,7 @@ import (
|
|||||||
utilwait "k8s.io/apimachinery/pkg/util/wait"
|
utilwait "k8s.io/apimachinery/pkg/util/wait"
|
||||||
"k8s.io/apiserver/pkg/admission"
|
"k8s.io/apiserver/pkg/admission"
|
||||||
webhookinit "k8s.io/apiserver/pkg/admission/plugin/webhook/initializer"
|
webhookinit "k8s.io/apiserver/pkg/admission/plugin/webhook/initializer"
|
||||||
|
"k8s.io/apiserver/pkg/cel/openapi/resolver"
|
||||||
genericapiserver "k8s.io/apiserver/pkg/server"
|
genericapiserver "k8s.io/apiserver/pkg/server"
|
||||||
egressselector "k8s.io/apiserver/pkg/server/egressselector"
|
egressselector "k8s.io/apiserver/pkg/server/egressselector"
|
||||||
"k8s.io/apiserver/pkg/util/webhook"
|
"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
|
// 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)
|
webhookAuthResolverWrapper := webhook.NewDefaultAuthenticationInfoResolverWrapper(proxyTransport, egressSelector, c.LoopbackClientConfig, tp)
|
||||||
webhookPluginInitializer := webhookinit.NewPluginInitializer(webhookAuthResolverWrapper, serviceResolver)
|
webhookPluginInitializer := webhookinit.NewPluginInitializer(webhookAuthResolverWrapper, serviceResolver)
|
||||||
|
|
||||||
@ -63,13 +64,13 @@ func (c *Config) New(proxyTransport *http.Transport, egressSelector *egressselec
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
discoveryClient := cacheddiscovery.NewMemCacheClient(clientset.Discovery())
|
discoveryClient := cacheddiscovery.NewMemCacheClient(clientset.Discovery())
|
||||||
discoveryRESTMapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient)
|
discoveryRESTMapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient)
|
||||||
kubePluginInitializer := NewPluginInitializer(
|
kubePluginInitializer := NewPluginInitializer(
|
||||||
cloudConfig,
|
cloudConfig,
|
||||||
discoveryRESTMapper,
|
discoveryRESTMapper,
|
||||||
quotainstall.NewQuotaConfigurationForAdmission(),
|
quotainstall.NewQuotaConfigurationForAdmission(),
|
||||||
|
schemaResolver,
|
||||||
)
|
)
|
||||||
|
|
||||||
admissionPostStartHook := func(context genericapiserver.PostStartHookContext) error {
|
admissionPostStartHook := func(context genericapiserver.PostStartHookContext) error {
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
"k8s.io/apiserver/pkg/admission"
|
"k8s.io/apiserver/pkg/admission"
|
||||||
"k8s.io/apiserver/pkg/admission/initializer"
|
"k8s.io/apiserver/pkg/admission/initializer"
|
||||||
|
"k8s.io/apiserver/pkg/cel/openapi/resolver"
|
||||||
quota "k8s.io/apiserver/pkg/quota/v1"
|
quota "k8s.io/apiserver/pkg/quota/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -35,6 +36,7 @@ type PluginInitializer struct {
|
|||||||
cloudConfig []byte
|
cloudConfig []byte
|
||||||
restMapper meta.RESTMapper
|
restMapper meta.RESTMapper
|
||||||
quotaConfiguration quota.Configuration
|
quotaConfiguration quota.Configuration
|
||||||
|
schemaResolver resolver.SchemaResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ admission.PluginInitializer = &PluginInitializer{}
|
var _ admission.PluginInitializer = &PluginInitializer{}
|
||||||
@ -46,11 +48,13 @@ func NewPluginInitializer(
|
|||||||
cloudConfig []byte,
|
cloudConfig []byte,
|
||||||
restMapper meta.RESTMapper,
|
restMapper meta.RESTMapper,
|
||||||
quotaConfiguration quota.Configuration,
|
quotaConfiguration quota.Configuration,
|
||||||
|
schemaResolver resolver.SchemaResolver,
|
||||||
) *PluginInitializer {
|
) *PluginInitializer {
|
||||||
return &PluginInitializer{
|
return &PluginInitializer{
|
||||||
cloudConfig: cloudConfig,
|
cloudConfig: cloudConfig,
|
||||||
restMapper: restMapper,
|
restMapper: restMapper,
|
||||||
quotaConfiguration: quotaConfiguration,
|
quotaConfiguration: quotaConfiguration,
|
||||||
|
schemaResolver: schemaResolver,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,4 +72,8 @@ func (i *PluginInitializer) Initialize(plugin admission.Interface) {
|
|||||||
if wants, ok := plugin.(initializer.WantsQuotaConfiguration); ok {
|
if wants, ok := plugin.(initializer.WantsQuotaConfiguration); ok {
|
||||||
wants.SetQuotaConfiguration(i.quotaConfiguration)
|
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) {
|
func TestCloudConfigAdmissionPlugin(t *testing.T) {
|
||||||
cloudConfig := []byte("cloud-configuration")
|
cloudConfig := []byte("cloud-configuration")
|
||||||
initializer := NewPluginInitializer(cloudConfig, nil, nil)
|
initializer := NewPluginInitializer(cloudConfig, nil, nil, nil)
|
||||||
wantsCloudConfigAdmission := &WantsCloudConfigAdmissionPlugin{}
|
wantsCloudConfigAdmission := &WantsCloudConfigAdmissionPlugin{}
|
||||||
initializer.Initialize(wantsCloudConfigAdmission)
|
initializer.Initialize(wantsCloudConfigAdmission)
|
||||||
|
|
||||||
@ -94,7 +94,7 @@ func (p *WantsRESTMapperAdmissionPlugin) SetRESTMapper(mapper meta.RESTMapper) {
|
|||||||
|
|
||||||
func TestRESTMapperAdmissionPlugin(t *testing.T) {
|
func TestRESTMapperAdmissionPlugin(t *testing.T) {
|
||||||
mapper := doNothingRESTMapper{}
|
mapper := doNothingRESTMapper{}
|
||||||
initializer := NewPluginInitializer(nil, mapper, nil)
|
initializer := NewPluginInitializer(nil, mapper, nil, nil)
|
||||||
wantsRESTMapperAdmission := &WantsRESTMapperAdmissionPlugin{}
|
wantsRESTMapperAdmission := &WantsRESTMapperAdmissionPlugin{}
|
||||||
initializer.Initialize(wantsRESTMapperAdmission)
|
initializer.Initialize(wantsRESTMapperAdmission)
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ func (p *WantsQuotaConfigurationAdmissionPlugin) SetQuotaConfiguration(config qu
|
|||||||
|
|
||||||
func TestQuotaConfigurationAdmissionPlugin(t *testing.T) {
|
func TestQuotaConfigurationAdmissionPlugin(t *testing.T) {
|
||||||
config := doNothingQuotaConfiguration{}
|
config := doNothingQuotaConfiguration{}
|
||||||
initializer := NewPluginInitializer(nil, nil, config)
|
initializer := NewPluginInitializer(nil, nil, config, nil)
|
||||||
wantsQuotaConfigurationAdmission := &WantsQuotaConfigurationAdmissionPlugin{}
|
wantsQuotaConfigurationAdmission := &WantsQuotaConfigurationAdmissionPlugin{}
|
||||||
initializer.Initialize(wantsQuotaConfigurationAdmission)
|
initializer.Initialize(wantsQuotaConfigurationAdmission)
|
||||||
|
|
||||||
|
@ -95,12 +95,13 @@ func (p RESTStorageProvider) v1alpha1Storage(apiResourceConfigSource serverstora
|
|||||||
|
|
||||||
// validatingadmissionpolicies
|
// validatingadmissionpolicies
|
||||||
if resource := "validatingadmissionpolicies"; apiResourceConfigSource.ResourceEnabled(admissionregistrationv1alpha1.SchemeGroupVersion.WithResource(resource)) {
|
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 {
|
if err != nil {
|
||||||
return storage, err
|
return storage, err
|
||||||
}
|
}
|
||||||
policyGetter = policyStorage
|
policyGetter = policyStorage
|
||||||
storage[resource] = policyStorage
|
storage[resource] = policyStorage
|
||||||
|
storage[resource+"/status"] = policyStatusStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
// validatingadmissionpolicybindings
|
// validatingadmissionpolicybindings
|
||||||
|
@ -17,6 +17,9 @@ limitations under the License.
|
|||||||
package storage
|
package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
"k8s.io/apiserver/pkg/registry/generic"
|
"k8s.io/apiserver/pkg/registry/generic"
|
||||||
@ -28,6 +31,7 @@ import (
|
|||||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||||
"k8s.io/kubernetes/pkg/registry/admissionregistration/resolver"
|
"k8s.io/kubernetes/pkg/registry/admissionregistration/resolver"
|
||||||
"k8s.io/kubernetes/pkg/registry/admissionregistration/validatingadmissionpolicy"
|
"k8s.io/kubernetes/pkg/registry/admissionregistration/validatingadmissionpolicy"
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// REST implements a RESTStorage for validatingAdmissionPolicy against etcd
|
// REST implements a RESTStorage for validatingAdmissionPolicy against etcd
|
||||||
@ -35,10 +39,16 @@ type REST struct {
|
|||||||
*genericregistry.Store
|
*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")
|
var groupResource = admissionregistration.Resource("validatingadmissionpolicies")
|
||||||
|
|
||||||
// NewREST returns a RESTStorage object that will work against validatingAdmissionPolicy.
|
// 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, error) {
|
func NewREST(optsGetter generic.RESTOptionsGetter, authorizer authorizer.Authorizer, resourceResolver resolver.ResourceResolver) (*REST, *StatusREST, error) {
|
||||||
r := &REST{}
|
r := &REST{}
|
||||||
strategy := validatingadmissionpolicy.NewStrategy(authorizer, resourceResolver)
|
strategy := validatingadmissionpolicy.NewStrategy(authorizer, resourceResolver)
|
||||||
store := &genericregistry.Store{
|
store := &genericregistry.Store{
|
||||||
@ -50,18 +60,24 @@ func NewREST(optsGetter generic.RESTOptionsGetter, authorizer authorizer.Authori
|
|||||||
DefaultQualifiedResource: groupResource,
|
DefaultQualifiedResource: groupResource,
|
||||||
SingularQualifiedResource: admissionregistration.Resource("validatingadmissionpolicy"),
|
SingularQualifiedResource: admissionregistration.Resource("validatingadmissionpolicy"),
|
||||||
|
|
||||||
CreateStrategy: strategy,
|
CreateStrategy: strategy,
|
||||||
UpdateStrategy: strategy,
|
UpdateStrategy: strategy,
|
||||||
DeleteStrategy: strategy,
|
DeleteStrategy: strategy,
|
||||||
|
ResetFieldsStrategy: strategy,
|
||||||
|
|
||||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||||
}
|
}
|
||||||
options := &generic.StoreOptions{RESTOptions: optsGetter}
|
options := &generic.StoreOptions{RESTOptions: optsGetter}
|
||||||
if err := store.CompleteWithOptions(options); err != nil {
|
if err := store.CompleteWithOptions(options); err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
r.Store = store
|
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
|
// Implement CategoriesProvider
|
||||||
@ -71,3 +87,34 @@ var _ rest.CategoriesProvider = &REST{}
|
|||||||
func (r *REST) Categories() []string {
|
func (r *REST) Categories() []string {
|
||||||
return []string{"api-extensions"}
|
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,
|
Decorator: generic.UndecoratedStorage,
|
||||||
DeleteCollectionWorkers: 1,
|
DeleteCollectionWorkers: 1,
|
||||||
ResourcePrefix: "validatingadmissionpolicies"}
|
ResourcePrefix: "validatingadmissionpolicies"}
|
||||||
storage, err := NewREST(restOptions, authorizer, resourceResolver)
|
storage, _, err := NewREST(restOptions, authorizer, resourceResolver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error from REST storage: %v", err)
|
t.Fatalf("unexpected error from REST storage: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,10 @@ package validatingadmissionpolicy
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||||
|
|
||||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
@ -56,6 +59,7 @@ func (v *validatingAdmissionPolicyStrategy) NamespaceScoped() bool {
|
|||||||
// PrepareForCreate clears the status of an validatingAdmissionPolicy before creation.
|
// PrepareForCreate clears the status of an validatingAdmissionPolicy before creation.
|
||||||
func (v *validatingAdmissionPolicyStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (v *validatingAdmissionPolicyStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
ic := obj.(*admissionregistration.ValidatingAdmissionPolicy)
|
ic := obj.(*admissionregistration.ValidatingAdmissionPolicy)
|
||||||
|
ic.Status = admissionregistration.ValidatingAdmissionPolicyStatus{}
|
||||||
ic.Generation = 1
|
ic.Generation = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,6 +68,9 @@ func (v *validatingAdmissionPolicyStrategy) PrepareForUpdate(ctx context.Context
|
|||||||
newIC := obj.(*admissionregistration.ValidatingAdmissionPolicy)
|
newIC := obj.(*admissionregistration.ValidatingAdmissionPolicy)
|
||||||
oldIC := old.(*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
|
// Any changes to the spec increment the generation number, any changes to the
|
||||||
// status should reflect the generation number of the corresponding object.
|
// status should reflect the generation number of the corresponding object.
|
||||||
// See metav1.ObjectMeta description for more information on Generation.
|
// 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 {
|
func (v *validatingAdmissionPolicyStrategy) AllowUnconditionalUpdate() bool {
|
||||||
return false
|
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}
|
||||||
|
}
|
||||||
|
@ -139,7 +139,7 @@ func newGCPermissionsEnforcement() (*gcPermissionsEnforcement, error) {
|
|||||||
return nil, fmt.Errorf("unexpected error while constructing resource list from fake discovery client: %v", err)
|
return nil, fmt.Errorf("unexpected error while constructing resource list from fake discovery client: %v", err)
|
||||||
}
|
}
|
||||||
restMapper := restmapper.NewDiscoveryRESTMapper(restMapperRes)
|
restMapper := restmapper.NewDiscoveryRESTMapper(restMapperRes)
|
||||||
pluginInitializer := kubeadmission.NewPluginInitializer(nil, restMapper, nil)
|
pluginInitializer := kubeadmission.NewPluginInitializer(nil, restMapper, nil, nil)
|
||||||
initializersChain := admission.PluginInitializers{}
|
initializersChain := admission.PluginInitializers{}
|
||||||
initializersChain = append(initializersChain, genericPluginInitializer)
|
initializersChain = append(initializersChain, genericPluginInitializer)
|
||||||
initializersChain = append(initializersChain, pluginInitializer)
|
initializersChain = append(initializersChain, pluginInitializer)
|
||||||
|
@ -111,7 +111,7 @@ func createHandlerWithConfig(kubeClient kubernetes.Interface, informerFactory in
|
|||||||
|
|
||||||
initializers := admission.PluginInitializers{
|
initializers := admission.PluginInitializers{
|
||||||
genericadmissioninitializer.New(kubeClient, nil, informerFactory, nil, nil, stopCh),
|
genericadmissioninitializer.New(kubeClient, nil, informerFactory, nil, nil, stopCh),
|
||||||
kubeapiserveradmission.NewPluginInitializer(nil, nil, quotaConfiguration),
|
kubeapiserveradmission.NewPluginInitializer(nil, nil, quotaConfiguration, nil),
|
||||||
}
|
}
|
||||||
initializers.Initialize(handler)
|
initializers.Initialize(handler)
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -66,6 +66,19 @@ message AuditAnnotation {
|
|||||||
optional string valueExpression = 2;
|
optional string valueExpression = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExpressionWarning is a warning information that targets a specific expression.
|
||||||
|
message ExpressionWarning {
|
||||||
|
// 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"
|
||||||
|
optional string fieldRef = 2;
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
optional string warning = 3;
|
||||||
|
}
|
||||||
|
|
||||||
// MatchResources decides whether to run the admission control policy on an object based
|
// MatchResources decides whether to run the admission control policy on an object based
|
||||||
// on whether it meets the match criteria.
|
// on whether it meets the match criteria.
|
||||||
// The exclude rules take precedence over include rules (if a resource matches both, it is excluded)
|
// The exclude rules take precedence over include rules (if a resource matches both, it is excluded)
|
||||||
@ -198,6 +211,15 @@ message ParamRef {
|
|||||||
optional string namespace = 2;
|
optional string namespace = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TypeChecking contains results of type checking the expressions in the
|
||||||
|
// ValidatingAdmissionPolicy
|
||||||
|
message TypeChecking {
|
||||||
|
// The type checking warnings for each expression.
|
||||||
|
// +optional
|
||||||
|
// +listType=atomic
|
||||||
|
repeated ExpressionWarning expressionWarnings = 1;
|
||||||
|
}
|
||||||
|
|
||||||
// ValidatingAdmissionPolicy describes the definition of an admission validation policy that accepts or rejects an object without changing it.
|
// ValidatingAdmissionPolicy describes the definition of an admission validation policy that accepts or rejects an object without changing it.
|
||||||
message ValidatingAdmissionPolicy {
|
message ValidatingAdmissionPolicy {
|
||||||
// Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata.
|
// Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata.
|
||||||
@ -206,6 +228,13 @@ message ValidatingAdmissionPolicy {
|
|||||||
|
|
||||||
// Specification of the desired behavior of the ValidatingAdmissionPolicy.
|
// Specification of the desired behavior of the ValidatingAdmissionPolicy.
|
||||||
optional ValidatingAdmissionPolicySpec spec = 2;
|
optional ValidatingAdmissionPolicySpec spec = 2;
|
||||||
|
|
||||||
|
// 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
|
||||||
|
optional ValidatingAdmissionPolicyStatus status = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidatingAdmissionPolicyBinding binds the ValidatingAdmissionPolicy with paramerized resources.
|
// ValidatingAdmissionPolicyBinding binds the ValidatingAdmissionPolicy with paramerized resources.
|
||||||
@ -353,6 +382,24 @@ message ValidatingAdmissionPolicySpec {
|
|||||||
repeated AuditAnnotation auditAnnotations = 5;
|
repeated AuditAnnotation auditAnnotations = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidatingAdmissionPolicyStatus represents the status of a ValidatingAdmissionPolicy.
|
||||||
|
message ValidatingAdmissionPolicyStatus {
|
||||||
|
// The generation observed by the controller.
|
||||||
|
// +optional
|
||||||
|
optional int64 observedGeneration = 1;
|
||||||
|
|
||||||
|
// The results of type checking for each expression.
|
||||||
|
// Presence of this field indicates the completion of the type checking.
|
||||||
|
// +optional
|
||||||
|
optional TypeChecking typeChecking = 2;
|
||||||
|
|
||||||
|
// The conditions represent the latest available observations of a policy's current state.
|
||||||
|
// +optional
|
||||||
|
// +listType=map
|
||||||
|
// +listMapKey=type
|
||||||
|
repeated k8s.io.apimachinery.pkg.apis.meta.v1.Condition conditions = 3;
|
||||||
|
}
|
||||||
|
|
||||||
// Validation specifies the CEL expression which is used to apply the validation.
|
// Validation specifies the CEL expression which is used to apply the validation.
|
||||||
message Validation {
|
message Validation {
|
||||||
// Expression represents the expression which will be evaluated by CEL.
|
// Expression represents the expression which will be evaluated by CEL.
|
||||||
|
@ -74,6 +74,49 @@ type ValidatingAdmissionPolicy struct {
|
|||||||
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||||
// Specification of the desired behavior of the ValidatingAdmissionPolicy.
|
// Specification of the desired behavior of the ValidatingAdmissionPolicy.
|
||||||
Spec ValidatingAdmissionPolicySpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
|
Spec ValidatingAdmissionPolicySpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
|
||||||
|
// 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 `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidatingAdmissionPolicyStatus represents the status of a ValidatingAdmissionPolicy.
|
||||||
|
type ValidatingAdmissionPolicyStatus struct {
|
||||||
|
// The generation observed by the controller.
|
||||||
|
// +optional
|
||||||
|
ObservedGeneration int64 `json:"observedGeneration,omitempty" protobuf:"varint,1,opt,name=observedGeneration"`
|
||||||
|
// The results of type checking for each expression.
|
||||||
|
// Presence of this field indicates the completion of the type checking.
|
||||||
|
// +optional
|
||||||
|
TypeChecking *TypeChecking `json:"typeChecking,omitempty" protobuf:"bytes,2,opt,name=typeChecking"`
|
||||||
|
// The conditions represent the latest available observations of a policy's current state.
|
||||||
|
// +optional
|
||||||
|
// +listType=map
|
||||||
|
// +listMapKey=type
|
||||||
|
Conditions []metav1.Condition `json:"conditions,omitempty" protobuf:"bytes,3,rep,name=conditions"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 `json:"expressionWarnings,omitempty" protobuf:"bytes,1,rep,name=expressionWarnings"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 `json:"fieldRef" protobuf:"bytes,2,opt,name=fieldRef"`
|
||||||
|
// 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 `json:"warning" protobuf:"bytes,3,opt,name=warning"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
|
@ -37,6 +37,16 @@ func (AuditAnnotation) SwaggerDoc() map[string]string {
|
|||||||
return map_AuditAnnotation
|
return map_AuditAnnotation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var map_ExpressionWarning = map[string]string{
|
||||||
|
"": "ExpressionWarning is a warning information that targets a specific expression.",
|
||||||
|
"fieldRef": "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\"",
|
||||||
|
"warning": "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.",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ExpressionWarning) SwaggerDoc() map[string]string {
|
||||||
|
return map_ExpressionWarning
|
||||||
|
}
|
||||||
|
|
||||||
var map_MatchResources = map[string]string{
|
var map_MatchResources = map[string]string{
|
||||||
"": "MatchResources decides whether to run the admission control policy on an object based on whether it meets the match criteria. The exclude rules take precedence over include rules (if a resource matches both, it is excluded)",
|
"": "MatchResources decides whether to run the admission control policy on an object based on whether it meets the match criteria. The exclude rules take precedence over include rules (if a resource matches both, it is excluded)",
|
||||||
"namespaceSelector": "NamespaceSelector decides whether to run the admission control policy on an object based on whether the namespace for that object matches the selector. If the object itself is a namespace, the matching is performed on object.metadata.labels. If the object is another cluster scoped resource, it never skips the policy.\n\nFor example, to run the webhook on any objects whose namespace is not associated with \"runlevel\" of \"0\" or \"1\"; you will set the selector as follows: \"namespaceSelector\": {\n \"matchExpressions\": [\n {\n \"key\": \"runlevel\",\n \"operator\": \"NotIn\",\n \"values\": [\n \"0\",\n \"1\"\n ]\n }\n ]\n}\n\nIf instead you want to only run the policy on any objects whose namespace is associated with the \"environment\" of \"prod\" or \"staging\"; you will set the selector as follows: \"namespaceSelector\": {\n \"matchExpressions\": [\n {\n \"key\": \"environment\",\n \"operator\": \"In\",\n \"values\": [\n \"prod\",\n \"staging\"\n ]\n }\n ]\n}\n\nSee https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ for more examples of label selectors.\n\nDefault to the empty LabelSelector, which matches everything.",
|
"namespaceSelector": "NamespaceSelector decides whether to run the admission control policy on an object based on whether the namespace for that object matches the selector. If the object itself is a namespace, the matching is performed on object.metadata.labels. If the object is another cluster scoped resource, it never skips the policy.\n\nFor example, to run the webhook on any objects whose namespace is not associated with \"runlevel\" of \"0\" or \"1\"; you will set the selector as follows: \"namespaceSelector\": {\n \"matchExpressions\": [\n {\n \"key\": \"runlevel\",\n \"operator\": \"NotIn\",\n \"values\": [\n \"0\",\n \"1\"\n ]\n }\n ]\n}\n\nIf instead you want to only run the policy on any objects whose namespace is associated with the \"environment\" of \"prod\" or \"staging\"; you will set the selector as follows: \"namespaceSelector\": {\n \"matchExpressions\": [\n {\n \"key\": \"environment\",\n \"operator\": \"In\",\n \"values\": [\n \"prod\",\n \"staging\"\n ]\n }\n ]\n}\n\nSee https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ for more examples of label selectors.\n\nDefault to the empty LabelSelector, which matches everything.",
|
||||||
@ -79,10 +89,20 @@ func (ParamRef) SwaggerDoc() map[string]string {
|
|||||||
return map_ParamRef
|
return map_ParamRef
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var map_TypeChecking = map[string]string{
|
||||||
|
"": "TypeChecking contains results of type checking the expressions in the ValidatingAdmissionPolicy",
|
||||||
|
"expressionWarnings": "The type checking warnings for each expression.",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (TypeChecking) SwaggerDoc() map[string]string {
|
||||||
|
return map_TypeChecking
|
||||||
|
}
|
||||||
|
|
||||||
var map_ValidatingAdmissionPolicy = map[string]string{
|
var map_ValidatingAdmissionPolicy = map[string]string{
|
||||||
"": "ValidatingAdmissionPolicy describes the definition of an admission validation policy that accepts or rejects an object without changing it.",
|
"": "ValidatingAdmissionPolicy describes the definition of an admission validation policy that accepts or rejects an object without changing it.",
|
||||||
"metadata": "Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata.",
|
"metadata": "Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata.",
|
||||||
"spec": "Specification of the desired behavior of the ValidatingAdmissionPolicy.",
|
"spec": "Specification of the desired behavior of the ValidatingAdmissionPolicy.",
|
||||||
|
"status": "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.",
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ValidatingAdmissionPolicy) SwaggerDoc() map[string]string {
|
func (ValidatingAdmissionPolicy) SwaggerDoc() map[string]string {
|
||||||
@ -144,6 +164,17 @@ func (ValidatingAdmissionPolicySpec) SwaggerDoc() map[string]string {
|
|||||||
return map_ValidatingAdmissionPolicySpec
|
return map_ValidatingAdmissionPolicySpec
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var map_ValidatingAdmissionPolicyStatus = map[string]string{
|
||||||
|
"": "ValidatingAdmissionPolicyStatus represents the status of a ValidatingAdmissionPolicy.",
|
||||||
|
"observedGeneration": "The generation observed by the controller.",
|
||||||
|
"typeChecking": "The results of type checking for each expression. Presence of this field indicates the completion of the type checking.",
|
||||||
|
"conditions": "The conditions represent the latest available observations of a policy's current state.",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ValidatingAdmissionPolicyStatus) SwaggerDoc() map[string]string {
|
||||||
|
return map_ValidatingAdmissionPolicyStatus
|
||||||
|
}
|
||||||
|
|
||||||
var map_Validation = map[string]string{
|
var map_Validation = map[string]string{
|
||||||
"": "Validation specifies the CEL expression which is used to apply the validation.",
|
"": "Validation specifies the CEL expression which is used to apply the validation.",
|
||||||
"expression": "Expression represents the expression which will be evaluated by CEL. ref: https://github.com/google/cel-spec CEL expressions have access to the contents of the API request/response, organized into CEL variables as well as some other useful variables:\n\n- 'object' - The object from the incoming request. The value is null for DELETE requests. - 'oldObject' - The existing object. The value is null for CREATE requests. - 'request' - Attributes of the API request([ref](/pkg/apis/admission/types.go#AdmissionRequest)). - 'params' - Parameter resource referred to by the policy binding being evaluated. Only populated if the policy has a ParamKind. - 'authorizer' - A CEL Authorizer. May be used to perform authorization checks for the principal (user or service account) of the request.\n See https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz\n- 'authorizer.requestResource' - A CEL ResourceCheck constructed from the 'authorizer' and configured with the\n request resource.\n\nThe `apiVersion`, `kind`, `metadata.name` and `metadata.generateName` are always accessible from the root of the object. No other metadata properties are accessible.\n\nOnly property names of the form `[a-zA-Z_.-/][a-zA-Z0-9_.-/]*` are accessible. Accessible property names are escaped according to the following rules when accessed in the expression: - '__' escapes to '__underscores__' - '.' escapes to '__dot__' - '-' escapes to '__dash__' - '/' escapes to '__slash__' - Property names that exactly match a CEL RESERVED keyword escape to '__{keyword}__'. The keywords are:\n\t \"true\", \"false\", \"null\", \"in\", \"as\", \"break\", \"const\", \"continue\", \"else\", \"for\", \"function\", \"if\",\n\t \"import\", \"let\", \"loop\", \"package\", \"namespace\", \"return\".\nExamples:\n - Expression accessing a property named \"namespace\": {\"Expression\": \"object.__namespace__ > 0\"}\n - Expression accessing a property named \"x-prop\": {\"Expression\": \"object.x__dash__prop > 0\"}\n - Expression accessing a property named \"redact__d\": {\"Expression\": \"object.redact__underscores__d > 0\"}\n\nEquality on arrays with list type of 'set' or 'map' ignores element order, i.e. [1, 2] == [2, 1]. Concatenation on arrays with x-kubernetes-list-type use the semantics of the list type:\n - 'set': `X + Y` performs a union where the array positions of all elements in `X` are preserved and\n non-intersecting elements in `Y` are appended, retaining their partial order.\n - 'map': `X + Y` performs a merge where the array positions of all keys in `X` are preserved but the values\n are overwritten by values in `Y` when the key sets of `X` and `Y` intersect. Elements in `Y` with\n non-intersecting keys are appended, retaining their partial order.\nRequired.",
|
"expression": "Expression represents the expression which will be evaluated by CEL. ref: https://github.com/google/cel-spec CEL expressions have access to the contents of the API request/response, organized into CEL variables as well as some other useful variables:\n\n- 'object' - The object from the incoming request. The value is null for DELETE requests. - 'oldObject' - The existing object. The value is null for CREATE requests. - 'request' - Attributes of the API request([ref](/pkg/apis/admission/types.go#AdmissionRequest)). - 'params' - Parameter resource referred to by the policy binding being evaluated. Only populated if the policy has a ParamKind. - 'authorizer' - A CEL Authorizer. May be used to perform authorization checks for the principal (user or service account) of the request.\n See https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz\n- 'authorizer.requestResource' - A CEL ResourceCheck constructed from the 'authorizer' and configured with the\n request resource.\n\nThe `apiVersion`, `kind`, `metadata.name` and `metadata.generateName` are always accessible from the root of the object. No other metadata properties are accessible.\n\nOnly property names of the form `[a-zA-Z_.-/][a-zA-Z0-9_.-/]*` are accessible. Accessible property names are escaped according to the following rules when accessed in the expression: - '__' escapes to '__underscores__' - '.' escapes to '__dot__' - '-' escapes to '__dash__' - '/' escapes to '__slash__' - Property names that exactly match a CEL RESERVED keyword escape to '__{keyword}__'. The keywords are:\n\t \"true\", \"false\", \"null\", \"in\", \"as\", \"break\", \"const\", \"continue\", \"else\", \"for\", \"function\", \"if\",\n\t \"import\", \"let\", \"loop\", \"package\", \"namespace\", \"return\".\nExamples:\n - Expression accessing a property named \"namespace\": {\"Expression\": \"object.__namespace__ > 0\"}\n - Expression accessing a property named \"x-prop\": {\"Expression\": \"object.x__dash__prop > 0\"}\n - Expression accessing a property named \"redact__d\": {\"Expression\": \"object.redact__underscores__d > 0\"}\n\nEquality on arrays with list type of 'set' or 'map' ignores element order, i.e. [1, 2] == [2, 1]. Concatenation on arrays with x-kubernetes-list-type use the semantics of the list type:\n - 'set': `X + Y` performs a union where the array positions of all elements in `X` are preserved and\n non-intersecting elements in `Y` are appended, retaining their partial order.\n - 'map': `X + Y` performs a merge where the array positions of all keys in `X` are preserved but the values\n are overwritten by values in `Y` when the key sets of `X` and `Y` intersect. Elements in `Y` with\n non-intersecting keys are appended, retaining their partial order.\nRequired.",
|
||||||
|
@ -42,6 +42,22 @@ func (in *AuditAnnotation) DeepCopy() *AuditAnnotation {
|
|||||||
return out
|
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.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *MatchResources) DeepCopyInto(out *MatchResources) {
|
func (in *MatchResources) DeepCopyInto(out *MatchResources) {
|
||||||
*out = *in
|
*out = *in
|
||||||
@ -141,12 +157,34 @@ func (in *ParamRef) DeepCopy() *ParamRef {
|
|||||||
return out
|
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.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *ValidatingAdmissionPolicy) DeepCopyInto(out *ValidatingAdmissionPolicy) {
|
func (in *ValidatingAdmissionPolicy) DeepCopyInto(out *ValidatingAdmissionPolicy) {
|
||||||
*out = *in
|
*out = *in
|
||||||
out.TypeMeta = in.TypeMeta
|
out.TypeMeta = in.TypeMeta
|
||||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
in.Spec.DeepCopyInto(&out.Spec)
|
in.Spec.DeepCopyInto(&out.Spec)
|
||||||
|
in.Status.DeepCopyInto(&out.Status)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,6 +373,34 @@ func (in *ValidatingAdmissionPolicySpec) DeepCopy() *ValidatingAdmissionPolicySp
|
|||||||
return out
|
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.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *Validation) DeepCopyInto(out *Validation) {
|
func (in *Validation) DeepCopyInto(out *Validation) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
@ -134,5 +134,26 @@
|
|||||||
"valueExpression": "valueExpressionValue"
|
"valueExpression": "valueExpressionValue"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"observedGeneration": 1,
|
||||||
|
"typeChecking": {
|
||||||
|
"expressionWarnings": [
|
||||||
|
{
|
||||||
|
"fieldRef": "fieldRefValue",
|
||||||
|
"warning": "warningValue"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"conditions": [
|
||||||
|
{
|
||||||
|
"type": "typeValue",
|
||||||
|
"status": "statusValue",
|
||||||
|
"observedGeneration": 3,
|
||||||
|
"lastTransitionTime": "2004-01-01T01:01:01Z",
|
||||||
|
"reason": "reasonValue",
|
||||||
|
"message": "messageValue"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
Binary file not shown.
@ -87,3 +87,16 @@ spec:
|
|||||||
message: messageValue
|
message: messageValue
|
||||||
messageExpression: messageExpressionValue
|
messageExpression: messageExpressionValue
|
||||||
reason: reasonValue
|
reason: reasonValue
|
||||||
|
status:
|
||||||
|
conditions:
|
||||||
|
- lastTransitionTime: "2004-01-01T01:01:01Z"
|
||||||
|
message: messageValue
|
||||||
|
observedGeneration: 3
|
||||||
|
reason: reasonValue
|
||||||
|
status: statusValue
|
||||||
|
type: typeValue
|
||||||
|
observedGeneration: 1
|
||||||
|
typeChecking:
|
||||||
|
expressionWarnings:
|
||||||
|
- fieldRef: fieldRefValue
|
||||||
|
warning: warningValue
|
||||||
|
@ -0,0 +1,132 @@
|
|||||||
|
{
|
||||||
|
"kind": "ValidatingAdmissionPolicy",
|
||||||
|
"apiVersion": "admissionregistration.k8s.io/v1alpha1",
|
||||||
|
"metadata": {
|
||||||
|
"name": "nameValue",
|
||||||
|
"generateName": "generateNameValue",
|
||||||
|
"namespace": "namespaceValue",
|
||||||
|
"selfLink": "selfLinkValue",
|
||||||
|
"uid": "uidValue",
|
||||||
|
"resourceVersion": "resourceVersionValue",
|
||||||
|
"generation": 7,
|
||||||
|
"creationTimestamp": "2008-01-01T01:01:01Z",
|
||||||
|
"deletionTimestamp": "2009-01-01T01:01:01Z",
|
||||||
|
"deletionGracePeriodSeconds": 10,
|
||||||
|
"labels": {
|
||||||
|
"labelsKey": "labelsValue"
|
||||||
|
},
|
||||||
|
"annotations": {
|
||||||
|
"annotationsKey": "annotationsValue"
|
||||||
|
},
|
||||||
|
"ownerReferences": [
|
||||||
|
{
|
||||||
|
"apiVersion": "apiVersionValue",
|
||||||
|
"kind": "kindValue",
|
||||||
|
"name": "nameValue",
|
||||||
|
"uid": "uidValue",
|
||||||
|
"controller": true,
|
||||||
|
"blockOwnerDeletion": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"finalizers": [
|
||||||
|
"finalizersValue"
|
||||||
|
],
|
||||||
|
"managedFields": [
|
||||||
|
{
|
||||||
|
"manager": "managerValue",
|
||||||
|
"operation": "operationValue",
|
||||||
|
"apiVersion": "apiVersionValue",
|
||||||
|
"time": "2004-01-01T01:01:01Z",
|
||||||
|
"fieldsType": "fieldsTypeValue",
|
||||||
|
"fieldsV1": {},
|
||||||
|
"subresource": "subresourceValue"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"paramKind": {
|
||||||
|
"apiVersion": "apiVersionValue",
|
||||||
|
"kind": "kindValue"
|
||||||
|
},
|
||||||
|
"matchConstraints": {
|
||||||
|
"namespaceSelector": {
|
||||||
|
"matchLabels": {
|
||||||
|
"matchLabelsKey": "matchLabelsValue"
|
||||||
|
},
|
||||||
|
"matchExpressions": [
|
||||||
|
{
|
||||||
|
"key": "keyValue",
|
||||||
|
"operator": "operatorValue",
|
||||||
|
"values": [
|
||||||
|
"valuesValue"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"objectSelector": {
|
||||||
|
"matchLabels": {
|
||||||
|
"matchLabelsKey": "matchLabelsValue"
|
||||||
|
},
|
||||||
|
"matchExpressions": [
|
||||||
|
{
|
||||||
|
"key": "keyValue",
|
||||||
|
"operator": "operatorValue",
|
||||||
|
"values": [
|
||||||
|
"valuesValue"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"resourceRules": [
|
||||||
|
{
|
||||||
|
"resourceNames": [
|
||||||
|
"resourceNamesValue"
|
||||||
|
],
|
||||||
|
"operations": [
|
||||||
|
"operationsValue"
|
||||||
|
],
|
||||||
|
"apiGroups": [
|
||||||
|
"apiGroupsValue"
|
||||||
|
],
|
||||||
|
"apiVersions": [
|
||||||
|
"apiVersionsValue"
|
||||||
|
],
|
||||||
|
"resources": [
|
||||||
|
"resourcesValue"
|
||||||
|
],
|
||||||
|
"scope": "scopeValue"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"excludeResourceRules": [
|
||||||
|
{
|
||||||
|
"resourceNames": [
|
||||||
|
"resourceNamesValue"
|
||||||
|
],
|
||||||
|
"operations": [
|
||||||
|
"operationsValue"
|
||||||
|
],
|
||||||
|
"apiGroups": [
|
||||||
|
"apiGroupsValue"
|
||||||
|
],
|
||||||
|
"apiVersions": [
|
||||||
|
"apiVersionsValue"
|
||||||
|
],
|
||||||
|
"resources": [
|
||||||
|
"resourcesValue"
|
||||||
|
],
|
||||||
|
"scope": "scopeValue"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"matchPolicy": "matchPolicyValue"
|
||||||
|
},
|
||||||
|
"validations": [
|
||||||
|
{
|
||||||
|
"expression": "expressionValue",
|
||||||
|
"message": "messageValue",
|
||||||
|
"reason": "reasonValue"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"failurePolicy": "failurePolicyValue"
|
||||||
|
},
|
||||||
|
"status": {}
|
||||||
|
}
|
Binary file not shown.
@ -0,0 +1,86 @@
|
|||||||
|
apiVersion: admissionregistration.k8s.io/v1alpha1
|
||||||
|
kind: ValidatingAdmissionPolicy
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
annotationsKey: annotationsValue
|
||||||
|
creationTimestamp: "2008-01-01T01:01:01Z"
|
||||||
|
deletionGracePeriodSeconds: 10
|
||||||
|
deletionTimestamp: "2009-01-01T01:01:01Z"
|
||||||
|
finalizers:
|
||||||
|
- finalizersValue
|
||||||
|
generateName: generateNameValue
|
||||||
|
generation: 7
|
||||||
|
labels:
|
||||||
|
labelsKey: labelsValue
|
||||||
|
managedFields:
|
||||||
|
- apiVersion: apiVersionValue
|
||||||
|
fieldsType: fieldsTypeValue
|
||||||
|
fieldsV1: {}
|
||||||
|
manager: managerValue
|
||||||
|
operation: operationValue
|
||||||
|
subresource: subresourceValue
|
||||||
|
time: "2004-01-01T01:01:01Z"
|
||||||
|
name: nameValue
|
||||||
|
namespace: namespaceValue
|
||||||
|
ownerReferences:
|
||||||
|
- apiVersion: apiVersionValue
|
||||||
|
blockOwnerDeletion: true
|
||||||
|
controller: true
|
||||||
|
kind: kindValue
|
||||||
|
name: nameValue
|
||||||
|
uid: uidValue
|
||||||
|
resourceVersion: resourceVersionValue
|
||||||
|
selfLink: selfLinkValue
|
||||||
|
uid: uidValue
|
||||||
|
spec:
|
||||||
|
failurePolicy: failurePolicyValue
|
||||||
|
matchConstraints:
|
||||||
|
excludeResourceRules:
|
||||||
|
- apiGroups:
|
||||||
|
- apiGroupsValue
|
||||||
|
apiVersions:
|
||||||
|
- apiVersionsValue
|
||||||
|
operations:
|
||||||
|
- operationsValue
|
||||||
|
resourceNames:
|
||||||
|
- resourceNamesValue
|
||||||
|
resources:
|
||||||
|
- resourcesValue
|
||||||
|
scope: scopeValue
|
||||||
|
matchPolicy: matchPolicyValue
|
||||||
|
namespaceSelector:
|
||||||
|
matchExpressions:
|
||||||
|
- key: keyValue
|
||||||
|
operator: operatorValue
|
||||||
|
values:
|
||||||
|
- valuesValue
|
||||||
|
matchLabels:
|
||||||
|
matchLabelsKey: matchLabelsValue
|
||||||
|
objectSelector:
|
||||||
|
matchExpressions:
|
||||||
|
- key: keyValue
|
||||||
|
operator: operatorValue
|
||||||
|
values:
|
||||||
|
- valuesValue
|
||||||
|
matchLabels:
|
||||||
|
matchLabelsKey: matchLabelsValue
|
||||||
|
resourceRules:
|
||||||
|
- apiGroups:
|
||||||
|
- apiGroupsValue
|
||||||
|
apiVersions:
|
||||||
|
- apiVersionsValue
|
||||||
|
operations:
|
||||||
|
- operationsValue
|
||||||
|
resourceNames:
|
||||||
|
- resourceNamesValue
|
||||||
|
resources:
|
||||||
|
- resourcesValue
|
||||||
|
scope: scopeValue
|
||||||
|
paramKind:
|
||||||
|
apiVersion: apiVersionValue
|
||||||
|
kind: kindValue
|
||||||
|
validations:
|
||||||
|
- expression: expressionValue
|
||||||
|
message: messageValue
|
||||||
|
reason: reasonValue
|
||||||
|
status: {}
|
@ -20,6 +20,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
"k8s.io/apiserver/pkg/admission"
|
"k8s.io/apiserver/pkg/admission"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
|
"k8s.io/apiserver/pkg/cel/openapi/resolver"
|
||||||
quota "k8s.io/apiserver/pkg/quota/v1"
|
quota "k8s.io/apiserver/pkg/quota/v1"
|
||||||
"k8s.io/client-go/dynamic"
|
"k8s.io/client-go/dynamic"
|
||||||
"k8s.io/client-go/informers"
|
"k8s.io/client-go/informers"
|
||||||
@ -81,3 +82,10 @@ type WantsRESTMapper interface {
|
|||||||
SetRESTMapper(meta.RESTMapper)
|
SetRESTMapper(meta.RESTMapper)
|
||||||
admission.InitializationValidator
|
admission.InitializationValidator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WantsSchemaResolver defines a function which sets the SchemaResolver for
|
||||||
|
// an admission plugin that needs it.
|
||||||
|
type WantsSchemaResolver interface {
|
||||||
|
SetSchemaResolver(resolver resolver.SchemaResolver)
|
||||||
|
admission.InitializationValidator
|
||||||
|
}
|
||||||
|
@ -81,7 +81,7 @@ func buildRequiredVarsEnv() (*cel.Env, error) {
|
|||||||
var propDecls []cel.EnvOption
|
var propDecls []cel.EnvOption
|
||||||
reg := apiservercel.NewRegistry(baseEnv)
|
reg := apiservercel.NewRegistry(baseEnv)
|
||||||
|
|
||||||
requestType := buildRequestType()
|
requestType := BuildRequestType()
|
||||||
rt, err := apiservercel.NewRuleTypes(requestType.TypeName(), requestType, reg)
|
rt, err := apiservercel.NewRuleTypes(requestType.TypeName(), requestType, reg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -134,11 +134,11 @@ func buildWithOptionalVarsEnvs(requiredVarsEnv *cel.Env) (envs, error) {
|
|||||||
return envs, nil
|
return envs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildRequestType generates a DeclType for AdmissionRequest. This may be replaced with a utility that
|
// BuildRequestType generates a DeclType for AdmissionRequest. This may be replaced with a utility that
|
||||||
// converts the native type definition to apiservercel.DeclType once such a utility becomes available.
|
// converts the native type definition to apiservercel.DeclType once such a utility becomes available.
|
||||||
// The 'uid' field is omitted since it is not needed for in-process admission review.
|
// The 'uid' field is omitted since it is not needed for in-process admission review.
|
||||||
// The 'object' and 'oldObject' fields are omitted since they are exposed as root level CEL variables.
|
// The 'object' and 'oldObject' fields are omitted since they are exposed as root level CEL variables.
|
||||||
func buildRequestType() *apiservercel.DeclType {
|
func BuildRequestType() *apiservercel.DeclType {
|
||||||
field := func(name string, declType *apiservercel.DeclType, required bool) *apiservercel.DeclField {
|
field := func(name string, declType *apiservercel.DeclType, required bool) *apiservercel.DeclField {
|
||||||
return apiservercel.NewDeclField(name, declType, required, nil, nil)
|
return apiservercel.NewDeclField(name, declType, required, nil, nil)
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
|
"k8s.io/apiserver/pkg/cel/openapi/resolver"
|
||||||
"k8s.io/apiserver/pkg/features"
|
"k8s.io/apiserver/pkg/features"
|
||||||
"k8s.io/client-go/dynamic"
|
"k8s.io/client-go/dynamic"
|
||||||
"k8s.io/component-base/featuregate"
|
"k8s.io/component-base/featuregate"
|
||||||
@ -73,6 +74,7 @@ type celAdmissionPlugin struct {
|
|||||||
dynamicClient dynamic.Interface
|
dynamicClient dynamic.Interface
|
||||||
stopCh <-chan struct{}
|
stopCh <-chan struct{}
|
||||||
authorizer authorizer.Authorizer
|
authorizer authorizer.Authorizer
|
||||||
|
schemaResolver resolver.SchemaResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ initializer.WantsExternalKubeInformerFactory = &celAdmissionPlugin{}
|
var _ initializer.WantsExternalKubeInformerFactory = &celAdmissionPlugin{}
|
||||||
@ -81,7 +83,7 @@ var _ initializer.WantsRESTMapper = &celAdmissionPlugin{}
|
|||||||
var _ initializer.WantsDynamicClient = &celAdmissionPlugin{}
|
var _ initializer.WantsDynamicClient = &celAdmissionPlugin{}
|
||||||
var _ initializer.WantsDrainedNotification = &celAdmissionPlugin{}
|
var _ initializer.WantsDrainedNotification = &celAdmissionPlugin{}
|
||||||
var _ initializer.WantsAuthorizer = &celAdmissionPlugin{}
|
var _ initializer.WantsAuthorizer = &celAdmissionPlugin{}
|
||||||
|
var _ initializer.WantsSchemaResolver = &celAdmissionPlugin{}
|
||||||
var _ admission.InitializationValidator = &celAdmissionPlugin{}
|
var _ admission.InitializationValidator = &celAdmissionPlugin{}
|
||||||
var _ admission.ValidationInterface = &celAdmissionPlugin{}
|
var _ admission.ValidationInterface = &celAdmissionPlugin{}
|
||||||
|
|
||||||
@ -115,6 +117,10 @@ func (c *celAdmissionPlugin) SetAuthorizer(authorizer authorizer.Authorizer) {
|
|||||||
c.authorizer = authorizer
|
c.authorizer = authorizer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *celAdmissionPlugin) SetSchemaResolver(resolver resolver.SchemaResolver) {
|
||||||
|
c.schemaResolver = resolver
|
||||||
|
}
|
||||||
|
|
||||||
func (c *celAdmissionPlugin) InspectFeatureGates(featureGates featuregate.FeatureGate) {
|
func (c *celAdmissionPlugin) InspectFeatureGates(featureGates featuregate.FeatureGate) {
|
||||||
if featureGates.Enabled(features.ValidatingAdmissionPolicy) {
|
if featureGates.Enabled(features.ValidatingAdmissionPolicy) {
|
||||||
c.enabled = true
|
c.enabled = true
|
||||||
@ -148,7 +154,7 @@ func (c *celAdmissionPlugin) ValidateInitialization() error {
|
|||||||
if c.authorizer == nil {
|
if c.authorizer == nil {
|
||||||
return errors.New("missing authorizer")
|
return errors.New("missing authorizer")
|
||||||
}
|
}
|
||||||
c.evaluator = NewAdmissionController(c.informerFactory, c.client, c.restMapper, c.dynamicClient, c.authorizer)
|
c.evaluator = NewAdmissionController(c.informerFactory, c.client, c.restMapper, c.schemaResolver /* (optional) */, c.dynamicClient, c.authorizer)
|
||||||
if err := c.evaluator.ValidateInitialization(); err != nil {
|
if err := c.evaluator.ValidateInitialization(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,7 @@ import (
|
|||||||
"k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/matching"
|
"k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/matching"
|
||||||
celconfig "k8s.io/apiserver/pkg/apis/cel"
|
celconfig "k8s.io/apiserver/pkg/apis/cel"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
|
"k8s.io/apiserver/pkg/cel/openapi/resolver"
|
||||||
"k8s.io/apiserver/pkg/warning"
|
"k8s.io/apiserver/pkg/warning"
|
||||||
"k8s.io/client-go/dynamic"
|
"k8s.io/client-go/dynamic"
|
||||||
"k8s.io/client-go/informers"
|
"k8s.io/client-go/informers"
|
||||||
@ -124,15 +125,21 @@ func NewAdmissionController(
|
|||||||
informerFactory informers.SharedInformerFactory,
|
informerFactory informers.SharedInformerFactory,
|
||||||
client kubernetes.Interface,
|
client kubernetes.Interface,
|
||||||
restMapper meta.RESTMapper,
|
restMapper meta.RESTMapper,
|
||||||
|
schemaResolver resolver.SchemaResolver,
|
||||||
dynamicClient dynamic.Interface,
|
dynamicClient dynamic.Interface,
|
||||||
authz authorizer.Authorizer,
|
authz authorizer.Authorizer,
|
||||||
) CELPolicyEvaluator {
|
) CELPolicyEvaluator {
|
||||||
|
var typeChecker *TypeChecker
|
||||||
|
if schemaResolver != nil {
|
||||||
|
typeChecker = &TypeChecker{schemaResolver: schemaResolver, restMapper: restMapper}
|
||||||
|
}
|
||||||
return &celAdmissionController{
|
return &celAdmissionController{
|
||||||
definitions: atomic.Value{},
|
definitions: atomic.Value{},
|
||||||
policyController: newPolicyController(
|
policyController: newPolicyController(
|
||||||
restMapper,
|
restMapper,
|
||||||
client,
|
client,
|
||||||
dynamicClient,
|
dynamicClient,
|
||||||
|
typeChecker,
|
||||||
cel.NewFilterCompiler(),
|
cel.NewFilterCompiler(),
|
||||||
NewMatcher(matching.NewMatcher(informerFactory.Core().V1().Namespaces().Lister(), client)),
|
NewMatcher(matching.NewMatcher(informerFactory.Core().V1().Namespaces().Lister(), client)),
|
||||||
generic.NewInformer[*v1alpha1.ValidatingAdmissionPolicy](
|
generic.NewInformer[*v1alpha1.ValidatingAdmissionPolicy](
|
||||||
|
@ -27,8 +27,10 @@ import (
|
|||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
celmetrics "k8s.io/apiserver/pkg/admission/cel"
|
celmetrics "k8s.io/apiserver/pkg/admission/cel"
|
||||||
"k8s.io/apiserver/pkg/admission/plugin/cel"
|
"k8s.io/apiserver/pkg/admission/plugin/cel"
|
||||||
@ -59,6 +61,11 @@ type policyController struct {
|
|||||||
|
|
||||||
newValidator
|
newValidator
|
||||||
|
|
||||||
|
// The TypeCheck checks the policy's expressions for type errors.
|
||||||
|
// Type of params is defined in policy.Spec.ParamsKind
|
||||||
|
// Types of object are calculated from policy.Spec.MatchingConstraints
|
||||||
|
typeChecker *TypeChecker
|
||||||
|
|
||||||
// Lock which protects:
|
// Lock which protects:
|
||||||
// - cachedPolicies
|
// - cachedPolicies
|
||||||
// - paramCRDControllers
|
// - paramCRDControllers
|
||||||
@ -98,6 +105,7 @@ func newPolicyController(
|
|||||||
restMapper meta.RESTMapper,
|
restMapper meta.RESTMapper,
|
||||||
client kubernetes.Interface,
|
client kubernetes.Interface,
|
||||||
dynamicClient dynamic.Interface,
|
dynamicClient dynamic.Interface,
|
||||||
|
typeChecker *TypeChecker,
|
||||||
filterCompiler cel.FilterCompiler,
|
filterCompiler cel.FilterCompiler,
|
||||||
matcher Matcher,
|
matcher Matcher,
|
||||||
policiesInformer generic.Informer[*v1alpha1.ValidatingAdmissionPolicy],
|
policiesInformer generic.Informer[*v1alpha1.ValidatingAdmissionPolicy],
|
||||||
@ -107,6 +115,7 @@ func newPolicyController(
|
|||||||
res := &policyController{}
|
res := &policyController{}
|
||||||
*res = policyController{
|
*res = policyController{
|
||||||
filterCompiler: filterCompiler,
|
filterCompiler: filterCompiler,
|
||||||
|
typeChecker: typeChecker,
|
||||||
definitionInfo: make(map[namespacedName]*definitionInfo),
|
definitionInfo: make(map[namespacedName]*definitionInfo),
|
||||||
bindingInfos: make(map[namespacedName]*bindingInfo),
|
bindingInfos: make(map[namespacedName]*bindingInfo),
|
||||||
paramsCRDControllers: make(map[v1alpha1.ParamKind]*paramInfo),
|
paramsCRDControllers: make(map[v1alpha1.ParamKind]*paramInfo),
|
||||||
@ -168,7 +177,17 @@ func (c *policyController) HasSynced() bool {
|
|||||||
func (c *policyController) reconcilePolicyDefinition(namespace, name string, definition *v1alpha1.ValidatingAdmissionPolicy) error {
|
func (c *policyController) reconcilePolicyDefinition(namespace, name string, definition *v1alpha1.ValidatingAdmissionPolicy) error {
|
||||||
c.mutex.Lock()
|
c.mutex.Lock()
|
||||||
defer c.mutex.Unlock()
|
defer c.mutex.Unlock()
|
||||||
|
err := c.reconcilePolicyDefinitionSpec(namespace, name, definition)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if c.typeChecker != nil {
|
||||||
|
err = c.reconcilePolicyStatus(namespace, name, definition)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *policyController) reconcilePolicyDefinitionSpec(namespace, name string, definition *v1alpha1.ValidatingAdmissionPolicy) error {
|
||||||
c.cachedPolicies = nil // invalidate cachedPolicies
|
c.cachedPolicies = nil // invalidate cachedPolicies
|
||||||
|
|
||||||
// Namespace for policydefinition is empty.
|
// Namespace for policydefinition is empty.
|
||||||
@ -423,6 +442,30 @@ func (c *policyController) reconcilePolicyBinding(namespace, name string, bindin
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *policyController) reconcilePolicyStatus(namespace, name string, definition *v1alpha1.ValidatingAdmissionPolicy) error {
|
||||||
|
if definition != nil && definition.Status.ObservedGeneration < definition.Generation {
|
||||||
|
st := c.calculatePolicyStatus(definition)
|
||||||
|
newDefinition := definition.DeepCopy()
|
||||||
|
newDefinition.Status = *st
|
||||||
|
_, err := c.client.AdmissionregistrationV1alpha1().ValidatingAdmissionPolicies().UpdateStatus(c.context, newDefinition, metav1.UpdateOptions{})
|
||||||
|
if err != nil {
|
||||||
|
// ignore error when the controller is not able to
|
||||||
|
// mutate the definition, and to avoid infinite requeue.
|
||||||
|
utilruntime.HandleError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *policyController) calculatePolicyStatus(definition *v1alpha1.ValidatingAdmissionPolicy) *v1alpha1.ValidatingAdmissionPolicyStatus {
|
||||||
|
expressionWarnings := c.typeChecker.Check(definition)
|
||||||
|
// modifying a deepcopy of the original status, preserving unrelated existing data
|
||||||
|
status := definition.Status.DeepCopy()
|
||||||
|
status.ObservedGeneration = definition.Generation
|
||||||
|
status.TypeChecking = &v1alpha1.TypeChecking{ExpressionWarnings: expressionWarnings}
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
|
||||||
func (c *policyController) reconcileParams(namespace, name string, params runtime.Object) error {
|
func (c *policyController) reconcileParams(namespace, name string, params runtime.Object) error {
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
// When we add informational type checking we will need to compile in the
|
// When we add informational type checking we will need to compile in the
|
||||||
|
@ -0,0 +1,435 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2023 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package validatingadmissionpolicy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/google/cel-go/cel"
|
||||||
|
"github.com/google/cel-go/common/types/ref"
|
||||||
|
|
||||||
|
"k8s.io/api/admissionregistration/v1alpha1"
|
||||||
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
|
plugincel "k8s.io/apiserver/pkg/admission/plugin/cel"
|
||||||
|
apiservercel "k8s.io/apiserver/pkg/cel"
|
||||||
|
"k8s.io/apiserver/pkg/cel/common"
|
||||||
|
"k8s.io/apiserver/pkg/cel/library"
|
||||||
|
"k8s.io/apiserver/pkg/cel/openapi"
|
||||||
|
"k8s.io/apiserver/pkg/cel/openapi/resolver"
|
||||||
|
"k8s.io/klog/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
const maxTypesToCheck = 10
|
||||||
|
|
||||||
|
type TypeChecker struct {
|
||||||
|
schemaResolver resolver.SchemaResolver
|
||||||
|
restMapper meta.RESTMapper
|
||||||
|
}
|
||||||
|
|
||||||
|
type typeOverwrite struct {
|
||||||
|
object *apiservercel.DeclType
|
||||||
|
params *apiservercel.DeclType
|
||||||
|
}
|
||||||
|
|
||||||
|
// typeCheckingResult holds the issues found during type checking, any returned
|
||||||
|
// error, and the gvk that the type checking is performed against.
|
||||||
|
type typeCheckingResult struct {
|
||||||
|
gvk schema.GroupVersionKind
|
||||||
|
|
||||||
|
issues *cel.Issues
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check preforms the type check against the given policy, and format the result
|
||||||
|
// as []ExpressionWarning that is ready to be set in policy.Status
|
||||||
|
// The result is nil if type checking returns no warning.
|
||||||
|
// The policy object is NOT mutated. The caller should update Status accordingly
|
||||||
|
func (c *TypeChecker) Check(policy *v1alpha1.ValidatingAdmissionPolicy) []v1alpha1.ExpressionWarning {
|
||||||
|
exps := make([]string, 0, len(policy.Spec.Validations))
|
||||||
|
// check main validation expressions, located in spec.validations[*]
|
||||||
|
fieldRef := field.NewPath("spec", "validations")
|
||||||
|
for _, v := range policy.Spec.Validations {
|
||||||
|
exps = append(exps, v.Expression)
|
||||||
|
}
|
||||||
|
msgs := c.CheckExpressions(exps, policy.Spec.ParamKind != nil, policy)
|
||||||
|
var results []v1alpha1.ExpressionWarning // intentionally not setting capacity
|
||||||
|
for i, msg := range msgs {
|
||||||
|
if msg != "" {
|
||||||
|
results = append(results, v1alpha1.ExpressionWarning{
|
||||||
|
FieldRef: fieldRef.Index(i).Child("expression").String(),
|
||||||
|
Warning: msg,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckExpressions checks a set of compiled CEL programs against the GVKs defined in
|
||||||
|
// policy.Spec.MatchConstraints
|
||||||
|
// The result is a human-readable form that describe which expressions
|
||||||
|
// violate what types at what place. The indexes of the return []string
|
||||||
|
// matches these of the input expressions.
|
||||||
|
// TODO: It is much more useful to have machine-readable output and let the
|
||||||
|
// client format it. That requires an update to the KEP, probably in coming
|
||||||
|
// releases.
|
||||||
|
func (c *TypeChecker) CheckExpressions(expressions []string, hasParams bool, policy *v1alpha1.ValidatingAdmissionPolicy) []string {
|
||||||
|
var allWarnings []string
|
||||||
|
allGvks := c.typesToCheck(policy)
|
||||||
|
gvks := make([]schema.GroupVersionKind, 0, len(allGvks))
|
||||||
|
schemas := make([]common.Schema, 0, len(allGvks))
|
||||||
|
for _, gvk := range allGvks {
|
||||||
|
s, err := c.schemaResolver.ResolveSchema(gvk)
|
||||||
|
if err != nil {
|
||||||
|
// type checking errors MUST NOT alter the behavior of the policy
|
||||||
|
// even if an error occurs.
|
||||||
|
if !errors.Is(err, resolver.ErrSchemaNotFound) {
|
||||||
|
// Anything except ErrSchemaNotFound is an internal error
|
||||||
|
klog.ErrorS(err, "internal error: schema resolution failure", "gvk", gvk)
|
||||||
|
}
|
||||||
|
// skip if an unrecoverable error occurs.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
gvks = append(gvks, gvk)
|
||||||
|
schemas = append(schemas, &openapi.Schema{Schema: s})
|
||||||
|
}
|
||||||
|
|
||||||
|
paramsType := c.paramsType(policy)
|
||||||
|
paramsDeclType, err := c.declType(paramsType)
|
||||||
|
if err != nil {
|
||||||
|
if !errors.Is(err, resolver.ErrSchemaNotFound) {
|
||||||
|
klog.V(2).ErrorS(err, "cannot resolve schema for params", "gvk", paramsType)
|
||||||
|
}
|
||||||
|
paramsDeclType = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, exp := range expressions {
|
||||||
|
var results []typeCheckingResult
|
||||||
|
for i, gvk := range gvks {
|
||||||
|
s := schemas[i]
|
||||||
|
issues, err := c.checkExpression(exp, hasParams, typeOverwrite{
|
||||||
|
object: common.SchemaDeclType(s, true),
|
||||||
|
params: paramsDeclType,
|
||||||
|
})
|
||||||
|
// save even if no issues are found, for the sake of formatting.
|
||||||
|
results = append(results, typeCheckingResult{
|
||||||
|
gvk: gvk,
|
||||||
|
issues: issues,
|
||||||
|
err: err,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
allWarnings = append(allWarnings, c.formatWarning(results))
|
||||||
|
}
|
||||||
|
|
||||||
|
return allWarnings
|
||||||
|
}
|
||||||
|
|
||||||
|
// formatWarning converts the resulting issues and possible error during
|
||||||
|
// type checking into a human-readable string
|
||||||
|
func (c *TypeChecker) formatWarning(results []typeCheckingResult) string {
|
||||||
|
var sb strings.Builder
|
||||||
|
for _, result := range results {
|
||||||
|
if result.issues == nil && result.err == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if result.err != nil {
|
||||||
|
sb.WriteString(fmt.Sprintf("%v: type checking error: %v\n", result.gvk, result.err))
|
||||||
|
} else {
|
||||||
|
sb.WriteString(fmt.Sprintf("%v: %s\n", result.gvk, result.issues))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.TrimSuffix(sb.String(), "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TypeChecker) declType(gvk schema.GroupVersionKind) (*apiservercel.DeclType, error) {
|
||||||
|
if gvk.Empty() {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
s, err := c.schemaResolver.ResolveSchema(gvk)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return common.SchemaDeclType(&openapi.Schema{Schema: s}, true), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TypeChecker) paramsType(policy *v1alpha1.ValidatingAdmissionPolicy) schema.GroupVersionKind {
|
||||||
|
if policy.Spec.ParamKind == nil {
|
||||||
|
return schema.GroupVersionKind{}
|
||||||
|
}
|
||||||
|
gv, err := schema.ParseGroupVersion(policy.Spec.ParamKind.APIVersion)
|
||||||
|
if err != nil {
|
||||||
|
return schema.GroupVersionKind{}
|
||||||
|
}
|
||||||
|
return gv.WithKind(policy.Spec.ParamKind.Kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TypeChecker) checkExpression(expression string, hasParams bool, types typeOverwrite) (*cel.Issues, error) {
|
||||||
|
env, err := buildEnv(hasParams, types)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// We cannot reuse an AST that is parsed by another env, so reparse it here.
|
||||||
|
// Compile = Parse + Check, we especially want the results of Check.
|
||||||
|
//
|
||||||
|
// Paradoxically, we discard the type-checked result and let the admission
|
||||||
|
// controller use the dynamic typed program.
|
||||||
|
// This is a compromise that is defined in the KEP. We can revisit this
|
||||||
|
// decision and expect a change with limited size.
|
||||||
|
_, issues := env.Compile(expression)
|
||||||
|
return issues, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// typesToCheck extracts a list of GVKs that needs type checking from the policy
|
||||||
|
// the result is sorted in the order of Group, Version, and Kind
|
||||||
|
func (c *TypeChecker) typesToCheck(p *v1alpha1.ValidatingAdmissionPolicy) []schema.GroupVersionKind {
|
||||||
|
gvks := sets.New[schema.GroupVersionKind]()
|
||||||
|
if p.Spec.MatchConstraints == nil || len(p.Spec.MatchConstraints.ResourceRules) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, rule := range p.Spec.MatchConstraints.ResourceRules {
|
||||||
|
groups := extractGroups(&rule.Rule)
|
||||||
|
if len(groups) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
versions := extractVersions(&rule.Rule)
|
||||||
|
if len(versions) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
resources := extractResources(&rule.Rule)
|
||||||
|
if len(resources) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// sort GVRs so that the loop below provides
|
||||||
|
// consistent results.
|
||||||
|
sort.Strings(groups)
|
||||||
|
sort.Strings(versions)
|
||||||
|
sort.Strings(resources)
|
||||||
|
count := 0
|
||||||
|
for _, group := range groups {
|
||||||
|
for _, version := range versions {
|
||||||
|
for _, resource := range resources {
|
||||||
|
gvr := schema.GroupVersionResource{
|
||||||
|
Group: group,
|
||||||
|
Version: version,
|
||||||
|
Resource: resource,
|
||||||
|
}
|
||||||
|
resolved, err := c.restMapper.KindsFor(gvr)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, r := range resolved {
|
||||||
|
if !r.Empty() {
|
||||||
|
gvks.Insert(r)
|
||||||
|
count++
|
||||||
|
// early return if maximum number of types are already
|
||||||
|
// collected
|
||||||
|
if count == maxTypesToCheck {
|
||||||
|
if gvks.Len() == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return sortGVKList(gvks.UnsortedList())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if gvks.Len() == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return sortGVKList(gvks.UnsortedList())
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractGroups(rule *v1alpha1.Rule) []string {
|
||||||
|
groups := make([]string, 0, len(rule.APIGroups))
|
||||||
|
for _, group := range rule.APIGroups {
|
||||||
|
// give up if wildcard
|
||||||
|
if strings.ContainsAny(group, "*") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
groups = append(groups, group)
|
||||||
|
}
|
||||||
|
return groups
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractVersions(rule *v1alpha1.Rule) []string {
|
||||||
|
versions := make([]string, 0, len(rule.APIVersions))
|
||||||
|
for _, version := range rule.APIVersions {
|
||||||
|
if strings.ContainsAny(version, "*") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
versions = append(versions, version)
|
||||||
|
}
|
||||||
|
return versions
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractResources(rule *v1alpha1.Rule) []string {
|
||||||
|
resources := make([]string, 0, len(rule.Resources))
|
||||||
|
for _, resource := range rule.Resources {
|
||||||
|
// skip wildcard and subresources
|
||||||
|
if strings.ContainsAny(resource, "*/") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
resources = append(resources, resource)
|
||||||
|
}
|
||||||
|
return resources
|
||||||
|
}
|
||||||
|
|
||||||
|
// sortGVKList sorts the list by Group, Version, and Kind
|
||||||
|
// returns the list itself.
|
||||||
|
func sortGVKList(list []schema.GroupVersionKind) []schema.GroupVersionKind {
|
||||||
|
sort.Slice(list, func(i, j int) bool {
|
||||||
|
if g := strings.Compare(list[i].Group, list[j].Group); g != 0 {
|
||||||
|
return g < 0
|
||||||
|
}
|
||||||
|
if v := strings.Compare(list[i].Version, list[j].Version); v != 0 {
|
||||||
|
return v < 0
|
||||||
|
}
|
||||||
|
return strings.Compare(list[i].Kind, list[j].Kind) < 0
|
||||||
|
})
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildEnv(hasParams bool, types typeOverwrite) (*cel.Env, error) {
|
||||||
|
baseEnv, err := getBaseEnv()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
reg := apiservercel.NewRegistry(baseEnv)
|
||||||
|
requestType := plugincel.BuildRequestType()
|
||||||
|
|
||||||
|
var varOpts []cel.EnvOption
|
||||||
|
var rts []*apiservercel.RuleTypes
|
||||||
|
|
||||||
|
// request, hand-crafted type
|
||||||
|
rt, opts, err := createRuleTypesAndOptions(reg, requestType, plugincel.RequestVarName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rts = append(rts, rt)
|
||||||
|
varOpts = append(varOpts, opts...)
|
||||||
|
|
||||||
|
// object and oldObject, same type, type(s) resolved from constraints
|
||||||
|
rt, opts, err = createRuleTypesAndOptions(reg, types.object, plugincel.ObjectVarName, plugincel.OldObjectVarName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rts = append(rts, rt)
|
||||||
|
varOpts = append(varOpts, opts...)
|
||||||
|
|
||||||
|
// params, defined by ParamKind
|
||||||
|
if hasParams {
|
||||||
|
rt, opts, err := createRuleTypesAndOptions(reg, types.params, plugincel.ParamsVarName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rts = append(rts, rt)
|
||||||
|
varOpts = append(varOpts, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
opts, err = ruleTypesOpts(rts, baseEnv.TypeProvider())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
opts = append(opts, varOpts...) // add variables after ruleTypes.
|
||||||
|
env, err := baseEnv.Extend(opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return env, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// createRuleTypeAndOptions creates the cel RuleTypes and a slice of EnvOption
|
||||||
|
// that can be used for creating a CEL env containing variables of declType.
|
||||||
|
// declType can be nil, in which case the variables will be of DynType.
|
||||||
|
func createRuleTypesAndOptions(registry *apiservercel.Registry, declType *apiservercel.DeclType, variables ...string) (*apiservercel.RuleTypes, []cel.EnvOption, error) {
|
||||||
|
opts := make([]cel.EnvOption, 0, len(variables))
|
||||||
|
// untyped, use DynType
|
||||||
|
if declType == nil {
|
||||||
|
for _, v := range variables {
|
||||||
|
opts = append(opts, cel.Variable(v, cel.DynType))
|
||||||
|
}
|
||||||
|
return nil, opts, nil
|
||||||
|
}
|
||||||
|
// create a RuleType for the given type
|
||||||
|
rt, err := apiservercel.NewRuleTypes(declType.TypeName(), declType, registry)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
if rt == nil {
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
for _, v := range variables {
|
||||||
|
opts = append(opts, cel.Variable(v, declType.CelType()))
|
||||||
|
}
|
||||||
|
return rt, opts, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ruleTypesOpts(ruleTypes []*apiservercel.RuleTypes, underlyingTypeProvider ref.TypeProvider) ([]cel.EnvOption, error) {
|
||||||
|
var providers []ref.TypeProvider // may be unused, too small to matter
|
||||||
|
var adapters []ref.TypeAdapter
|
||||||
|
for _, rt := range ruleTypes {
|
||||||
|
if rt != nil {
|
||||||
|
withTP, err := rt.WithTypeProvider(underlyingTypeProvider)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
providers = append(providers, withTP)
|
||||||
|
adapters = append(adapters, withTP)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var tp ref.TypeProvider
|
||||||
|
var ta ref.TypeAdapter
|
||||||
|
switch len(providers) {
|
||||||
|
case 0:
|
||||||
|
return nil, nil
|
||||||
|
case 1:
|
||||||
|
tp = providers[0]
|
||||||
|
ta = adapters[0]
|
||||||
|
default:
|
||||||
|
tp = &apiservercel.CompositedTypeProvider{Providers: providers}
|
||||||
|
ta = &apiservercel.CompositedTypeAdapter{Adapters: adapters}
|
||||||
|
}
|
||||||
|
return []cel.EnvOption{cel.CustomTypeProvider(tp), cel.CustomTypeAdapter(ta)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBaseEnv() (*cel.Env, error) {
|
||||||
|
typeCheckingBaseEnvInit.Do(func() {
|
||||||
|
var opts []cel.EnvOption
|
||||||
|
opts = append(opts, cel.HomogeneousAggregateLiterals())
|
||||||
|
// Validate function declarations once during base env initialization,
|
||||||
|
// so they don't need to be evaluated each time a CEL rule is compiled.
|
||||||
|
// This is a relatively expensive operation.
|
||||||
|
opts = append(opts, cel.EagerlyValidateDeclarations(true), cel.DefaultUTCTimeZone(true))
|
||||||
|
opts = append(opts, library.ExtensionLibs...)
|
||||||
|
typeCheckingBaseEnv, typeCheckingBaseEnvError = cel.NewEnv(opts...)
|
||||||
|
})
|
||||||
|
return typeCheckingBaseEnv, typeCheckingBaseEnvError
|
||||||
|
}
|
||||||
|
|
||||||
|
var typeCheckingBaseEnv *cel.Env
|
||||||
|
var typeCheckingBaseEnvError error
|
||||||
|
var typeCheckingBaseEnvInit sync.Once
|
@ -0,0 +1,409 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2023 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package validatingadmissionpolicy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/api/admissionregistration/v1alpha1"
|
||||||
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/apiserver/pkg/cel/openapi/resolver"
|
||||||
|
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestExtractTypeNames(t *testing.T) {
|
||||||
|
for _, tc := range []struct {
|
||||||
|
name string
|
||||||
|
policy *v1alpha1.ValidatingAdmissionPolicy
|
||||||
|
expected []schema.GroupVersionKind // must be sorted
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
policy: &v1alpha1.ValidatingAdmissionPolicy{},
|
||||||
|
expected: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "specific",
|
||||||
|
policy: &v1alpha1.ValidatingAdmissionPolicy{Spec: v1alpha1.ValidatingAdmissionPolicySpec{
|
||||||
|
MatchConstraints: &v1alpha1.MatchResources{ResourceRules: []v1alpha1.NamedRuleWithOperations{
|
||||||
|
{
|
||||||
|
RuleWithOperations: v1alpha1.RuleWithOperations{
|
||||||
|
Rule: v1alpha1.Rule{
|
||||||
|
APIGroups: []string{"apps"},
|
||||||
|
APIVersions: []string{"v1"},
|
||||||
|
Resources: []string{"deployments"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
expected: []schema.GroupVersionKind{{
|
||||||
|
Group: "apps",
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "Deployment",
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple",
|
||||||
|
policy: &v1alpha1.ValidatingAdmissionPolicy{Spec: v1alpha1.ValidatingAdmissionPolicySpec{
|
||||||
|
MatchConstraints: &v1alpha1.MatchResources{ResourceRules: []v1alpha1.NamedRuleWithOperations{
|
||||||
|
{
|
||||||
|
RuleWithOperations: v1alpha1.RuleWithOperations{
|
||||||
|
Rule: v1alpha1.Rule{
|
||||||
|
APIGroups: []string{"apps"},
|
||||||
|
APIVersions: []string{"v1"},
|
||||||
|
Resources: []string{"deployments"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
RuleWithOperations: v1alpha1.RuleWithOperations{
|
||||||
|
Rule: v1alpha1.Rule{
|
||||||
|
APIGroups: []string{""},
|
||||||
|
APIVersions: []string{"v1"},
|
||||||
|
Resources: []string{"pods"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
expected: []schema.GroupVersionKind{
|
||||||
|
{
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "Pod",
|
||||||
|
}, {
|
||||||
|
Group: "apps",
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "Deployment",
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "all resources",
|
||||||
|
policy: &v1alpha1.ValidatingAdmissionPolicy{Spec: v1alpha1.ValidatingAdmissionPolicySpec{
|
||||||
|
MatchConstraints: &v1alpha1.MatchResources{ResourceRules: []v1alpha1.NamedRuleWithOperations{
|
||||||
|
{
|
||||||
|
RuleWithOperations: v1alpha1.RuleWithOperations{
|
||||||
|
Rule: v1alpha1.Rule{
|
||||||
|
APIGroups: []string{"apps"},
|
||||||
|
APIVersions: []string{"v1"},
|
||||||
|
Resources: []string{"*"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
expected: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "sub resources",
|
||||||
|
policy: &v1alpha1.ValidatingAdmissionPolicy{Spec: v1alpha1.ValidatingAdmissionPolicySpec{
|
||||||
|
MatchConstraints: &v1alpha1.MatchResources{ResourceRules: []v1alpha1.NamedRuleWithOperations{
|
||||||
|
{
|
||||||
|
RuleWithOperations: v1alpha1.RuleWithOperations{
|
||||||
|
Rule: v1alpha1.Rule{
|
||||||
|
APIGroups: []string{"apps"},
|
||||||
|
APIVersions: []string{"v1"},
|
||||||
|
Resources: []string{"pods/*"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
expected: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "mixtures",
|
||||||
|
policy: &v1alpha1.ValidatingAdmissionPolicy{Spec: v1alpha1.ValidatingAdmissionPolicySpec{
|
||||||
|
MatchConstraints: &v1alpha1.MatchResources{ResourceRules: []v1alpha1.NamedRuleWithOperations{
|
||||||
|
{
|
||||||
|
RuleWithOperations: v1alpha1.RuleWithOperations{
|
||||||
|
Rule: v1alpha1.Rule{
|
||||||
|
APIGroups: []string{"apps"},
|
||||||
|
APIVersions: []string{"v1"},
|
||||||
|
Resources: []string{"deployments"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RuleWithOperations: v1alpha1.RuleWithOperations{
|
||||||
|
Rule: v1alpha1.Rule{
|
||||||
|
APIGroups: []string{"apps"},
|
||||||
|
APIVersions: []string{"*"},
|
||||||
|
Resources: []string{"deployments"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
expected: []schema.GroupVersionKind{{
|
||||||
|
Group: "apps",
|
||||||
|
Version: "v1",
|
||||||
|
Kind: "Deployment",
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
typeChecker := buildTypeChecker(nil)
|
||||||
|
got := typeChecker.typesToCheck(tc.policy)
|
||||||
|
if !reflect.DeepEqual(tc.expected, got) {
|
||||||
|
t.Errorf("expected %v but got %v", tc.expected, got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTypeCheck(t *testing.T) {
|
||||||
|
deploymentPolicy := &v1alpha1.ValidatingAdmissionPolicy{Spec: v1alpha1.ValidatingAdmissionPolicySpec{
|
||||||
|
Validations: []v1alpha1.Validation{
|
||||||
|
{
|
||||||
|
Expression: "object.foo == 'bar'",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MatchConstraints: &v1alpha1.MatchResources{ResourceRules: []v1alpha1.NamedRuleWithOperations{
|
||||||
|
{
|
||||||
|
RuleWithOperations: v1alpha1.RuleWithOperations{
|
||||||
|
Rule: v1alpha1.Rule{
|
||||||
|
APIGroups: []string{"apps"},
|
||||||
|
APIVersions: []string{"v1"},
|
||||||
|
Resources: []string{"deployments"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
}}
|
||||||
|
multiExpressionPolicy := &v1alpha1.ValidatingAdmissionPolicy{Spec: v1alpha1.ValidatingAdmissionPolicySpec{
|
||||||
|
Validations: []v1alpha1.Validation{
|
||||||
|
{
|
||||||
|
Expression: "object.foo == 'bar'",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Expression: "object.bar == 'foo'",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MatchConstraints: &v1alpha1.MatchResources{ResourceRules: []v1alpha1.NamedRuleWithOperations{
|
||||||
|
{
|
||||||
|
RuleWithOperations: v1alpha1.RuleWithOperations{
|
||||||
|
Rule: v1alpha1.Rule{
|
||||||
|
APIGroups: []string{"apps"},
|
||||||
|
APIVersions: []string{"v1"},
|
||||||
|
Resources: []string{"deployments"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
}}
|
||||||
|
paramsRefPolicy := &v1alpha1.ValidatingAdmissionPolicy{Spec: v1alpha1.ValidatingAdmissionPolicySpec{
|
||||||
|
ParamKind: &v1alpha1.ParamKind{
|
||||||
|
APIVersion: "v1",
|
||||||
|
Kind: "DoesNotMatter",
|
||||||
|
},
|
||||||
|
Validations: []v1alpha1.Validation{
|
||||||
|
{
|
||||||
|
Expression: "object.foo == params.bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MatchConstraints: &v1alpha1.MatchResources{ResourceRules: []v1alpha1.NamedRuleWithOperations{
|
||||||
|
{
|
||||||
|
RuleWithOperations: v1alpha1.RuleWithOperations{
|
||||||
|
Rule: v1alpha1.Rule{
|
||||||
|
APIGroups: []string{"apps"},
|
||||||
|
APIVersions: []string{"v1"},
|
||||||
|
Resources: []string{"deployments"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
}}
|
||||||
|
for _, tc := range []struct {
|
||||||
|
name string
|
||||||
|
schemaToReturn *spec.Schema
|
||||||
|
policy *v1alpha1.ValidatingAdmissionPolicy
|
||||||
|
assertions []assertionFunc
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
policy: &v1alpha1.ValidatingAdmissionPolicy{},
|
||||||
|
assertions: []assertionFunc{toBeEmpty},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "unresolved schema",
|
||||||
|
policy: deploymentPolicy,
|
||||||
|
schemaToReturn: nil,
|
||||||
|
assertions: []assertionFunc{toBeEmpty},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "passed check",
|
||||||
|
policy: deploymentPolicy,
|
||||||
|
schemaToReturn: &spec.Schema{
|
||||||
|
SchemaProps: spec.SchemaProps{
|
||||||
|
Type: []string{"object"},
|
||||||
|
Properties: map[string]spec.Schema{
|
||||||
|
"foo": *spec.StringProperty(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
assertions: []assertionFunc{toBeEmpty},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "undefined field",
|
||||||
|
policy: deploymentPolicy,
|
||||||
|
schemaToReturn: &spec.Schema{
|
||||||
|
SchemaProps: spec.SchemaProps{
|
||||||
|
Type: []string{"object"},
|
||||||
|
Properties: map[string]spec.Schema{
|
||||||
|
"bar": *spec.StringProperty(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
assertions: []assertionFunc{
|
||||||
|
toHaveFieldRef("spec.validations[0].expression"),
|
||||||
|
toContain(`undefined field 'foo'`),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "field type mismatch",
|
||||||
|
policy: deploymentPolicy,
|
||||||
|
schemaToReturn: &spec.Schema{
|
||||||
|
SchemaProps: spec.SchemaProps{
|
||||||
|
Type: []string{"object"},
|
||||||
|
Properties: map[string]spec.Schema{
|
||||||
|
"foo": *spec.Int64Property(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
assertions: []assertionFunc{
|
||||||
|
toHaveFieldRef("spec.validations[0].expression"),
|
||||||
|
toContain(`found no matching overload`),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "params",
|
||||||
|
policy: paramsRefPolicy,
|
||||||
|
schemaToReturn: &spec.Schema{
|
||||||
|
SchemaProps: spec.SchemaProps{
|
||||||
|
Type: []string{"object"},
|
||||||
|
Properties: map[string]spec.Schema{
|
||||||
|
"foo": *spec.StringProperty(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
assertions: []assertionFunc{
|
||||||
|
toHaveFieldRef("spec.validations[0].expression"),
|
||||||
|
toContain(`undefined field 'bar'`),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple expressions",
|
||||||
|
policy: multiExpressionPolicy,
|
||||||
|
schemaToReturn: &spec.Schema{
|
||||||
|
SchemaProps: spec.SchemaProps{
|
||||||
|
Type: []string{"object"},
|
||||||
|
Properties: map[string]spec.Schema{
|
||||||
|
"foo": *spec.StringProperty(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
assertions: []assertionFunc{
|
||||||
|
toHaveFieldRef("spec.validations[1].expression"), // expressions[0] is okay, [1] is wrong
|
||||||
|
toHaveLengthOf(1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
typeChecker := buildTypeChecker(tc.schemaToReturn)
|
||||||
|
warnings := typeChecker.Check(tc.policy)
|
||||||
|
for _, a := range tc.assertions {
|
||||||
|
a(warnings, t)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildTypeChecker(schemaToReturn *spec.Schema) *TypeChecker {
|
||||||
|
restMapper := meta.NewDefaultRESTMapper([]schema.GroupVersion{
|
||||||
|
{
|
||||||
|
Group: "",
|
||||||
|
Version: "v1",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
restMapper.Add(must3(scheme.ObjectKinds(&corev1.Pod{}))[0], meta.RESTScopeRoot)
|
||||||
|
restMapper.Add(must3(scheme.ObjectKinds(&appsv1.Deployment{}))[0], meta.RESTScopeRoot)
|
||||||
|
|
||||||
|
return &TypeChecker{
|
||||||
|
schemaResolver: &fakeSchemaResolver{schemaToReturn: schemaToReturn},
|
||||||
|
restMapper: restMapper,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type fakeSchemaResolver struct {
|
||||||
|
schemaToReturn *spec.Schema
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *fakeSchemaResolver) ResolveSchema(gvk schema.GroupVersionKind) (*spec.Schema, error) {
|
||||||
|
if r.schemaToReturn == nil {
|
||||||
|
return nil, fmt.Errorf("cannot resolve for %v: %w", gvk, resolver.ErrSchemaNotFound)
|
||||||
|
}
|
||||||
|
return r.schemaToReturn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func toBeEmpty(warnings []v1alpha1.ExpressionWarning, t *testing.T) {
|
||||||
|
if len(warnings) != 0 {
|
||||||
|
t.Fatalf("expected empty but got %v", warnings)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toContain(substring string) func(warnings []v1alpha1.ExpressionWarning, t *testing.T) {
|
||||||
|
return func(warnings []v1alpha1.ExpressionWarning, t *testing.T) {
|
||||||
|
if len(warnings) == 0 {
|
||||||
|
t.Errorf("expected containing %q but got empty", substring)
|
||||||
|
}
|
||||||
|
for i, w := range warnings {
|
||||||
|
if !strings.Contains(w.Warning, substring) {
|
||||||
|
t.Errorf("warning %d does not contain %q, got %v", i, substring, w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toHaveLengthOf(expected int) func(warnings []v1alpha1.ExpressionWarning, t *testing.T) {
|
||||||
|
return func(warnings []v1alpha1.ExpressionWarning, t *testing.T) {
|
||||||
|
got := len(warnings)
|
||||||
|
if expected != got {
|
||||||
|
t.Errorf("expect warnings to have length of %d, but got %d", expected, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toHaveFieldRef(paths ...string) func(warnings []v1alpha1.ExpressionWarning, t *testing.T) {
|
||||||
|
return func(warnings []v1alpha1.ExpressionWarning, t *testing.T) {
|
||||||
|
if len(paths) != len(warnings) {
|
||||||
|
t.Errorf("expect warnings to have length of %d, but got %d", len(paths), len(warnings))
|
||||||
|
}
|
||||||
|
for i := range paths {
|
||||||
|
if paths[i] != warnings[i].FieldRef {
|
||||||
|
t.Errorf("wrong fieldRef at %d, expected %q but got %q", i, paths[i], warnings[i].FieldRef)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type assertionFunc func(warnings []v1alpha1.ExpressionWarning, t *testing.T)
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
Copyright The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Code generated by applyconfiguration-gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package v1alpha1
|
||||||
|
|
||||||
|
// ExpressionWarningApplyConfiguration represents an declarative configuration of the ExpressionWarning type for use
|
||||||
|
// with apply.
|
||||||
|
type ExpressionWarningApplyConfiguration struct {
|
||||||
|
FieldRef *string `json:"fieldRef,omitempty"`
|
||||||
|
Warning *string `json:"warning,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExpressionWarningApplyConfiguration constructs an declarative configuration of the ExpressionWarning type for use with
|
||||||
|
// apply.
|
||||||
|
func ExpressionWarning() *ExpressionWarningApplyConfiguration {
|
||||||
|
return &ExpressionWarningApplyConfiguration{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithFieldRef sets the FieldRef 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 FieldRef field is set to the value of the last call.
|
||||||
|
func (b *ExpressionWarningApplyConfiguration) WithFieldRef(value string) *ExpressionWarningApplyConfiguration {
|
||||||
|
b.FieldRef = &value
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithWarning sets the Warning 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 Warning field is set to the value of the last call.
|
||||||
|
func (b *ExpressionWarningApplyConfiguration) WithWarning(value string) *ExpressionWarningApplyConfiguration {
|
||||||
|
b.Warning = &value
|
||||||
|
return b
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
Copyright The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Code generated by applyconfiguration-gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package v1alpha1
|
||||||
|
|
||||||
|
// TypeCheckingApplyConfiguration represents an declarative configuration of the TypeChecking type for use
|
||||||
|
// with apply.
|
||||||
|
type TypeCheckingApplyConfiguration struct {
|
||||||
|
ExpressionWarnings []ExpressionWarningApplyConfiguration `json:"expressionWarnings,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TypeCheckingApplyConfiguration constructs an declarative configuration of the TypeChecking type for use with
|
||||||
|
// apply.
|
||||||
|
func TypeChecking() *TypeCheckingApplyConfiguration {
|
||||||
|
return &TypeCheckingApplyConfiguration{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithExpressionWarnings adds the given value to the ExpressionWarnings field in the declarative configuration
|
||||||
|
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
|
||||||
|
// If called multiple times, values provided by each call will be appended to the ExpressionWarnings field.
|
||||||
|
func (b *TypeCheckingApplyConfiguration) WithExpressionWarnings(values ...*ExpressionWarningApplyConfiguration) *TypeCheckingApplyConfiguration {
|
||||||
|
for i := range values {
|
||||||
|
if values[i] == nil {
|
||||||
|
panic("nil value passed to WithExpressionWarnings")
|
||||||
|
}
|
||||||
|
b.ExpressionWarnings = append(b.ExpressionWarnings, *values[i])
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
@ -32,7 +32,8 @@ import (
|
|||||||
type ValidatingAdmissionPolicyApplyConfiguration struct {
|
type ValidatingAdmissionPolicyApplyConfiguration struct {
|
||||||
v1.TypeMetaApplyConfiguration `json:",inline"`
|
v1.TypeMetaApplyConfiguration `json:",inline"`
|
||||||
*v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"`
|
*v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"`
|
||||||
Spec *ValidatingAdmissionPolicySpecApplyConfiguration `json:"spec,omitempty"`
|
Spec *ValidatingAdmissionPolicySpecApplyConfiguration `json:"spec,omitempty"`
|
||||||
|
Status *ValidatingAdmissionPolicyStatusApplyConfiguration `json:"status,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidatingAdmissionPolicy constructs an declarative configuration of the ValidatingAdmissionPolicy type for use with
|
// ValidatingAdmissionPolicy constructs an declarative configuration of the ValidatingAdmissionPolicy type for use with
|
||||||
@ -245,3 +246,11 @@ func (b *ValidatingAdmissionPolicyApplyConfiguration) WithSpec(value *Validating
|
|||||||
b.Spec = value
|
b.Spec = value
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithStatus sets the Status 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 Status field is set to the value of the last call.
|
||||||
|
func (b *ValidatingAdmissionPolicyApplyConfiguration) WithStatus(value *ValidatingAdmissionPolicyStatusApplyConfiguration) *ValidatingAdmissionPolicyApplyConfiguration {
|
||||||
|
b.Status = value
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
Copyright The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Code generated by applyconfiguration-gen. DO NOT EDIT.
|
||||||
|
|
||||||
|
package v1alpha1
|
||||||
|
|
||||||
|
import (
|
||||||
|
v1 "k8s.io/client-go/applyconfigurations/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ValidatingAdmissionPolicyStatusApplyConfiguration represents an declarative configuration of the ValidatingAdmissionPolicyStatus type for use
|
||||||
|
// with apply.
|
||||||
|
type ValidatingAdmissionPolicyStatusApplyConfiguration struct {
|
||||||
|
ObservedGeneration *int64 `json:"observedGeneration,omitempty"`
|
||||||
|
TypeChecking *TypeCheckingApplyConfiguration `json:"typeChecking,omitempty"`
|
||||||
|
Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidatingAdmissionPolicyStatusApplyConfiguration constructs an declarative configuration of the ValidatingAdmissionPolicyStatus type for use with
|
||||||
|
// apply.
|
||||||
|
func ValidatingAdmissionPolicyStatus() *ValidatingAdmissionPolicyStatusApplyConfiguration {
|
||||||
|
return &ValidatingAdmissionPolicyStatusApplyConfiguration{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithObservedGeneration sets the ObservedGeneration 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 ObservedGeneration field is set to the value of the last call.
|
||||||
|
func (b *ValidatingAdmissionPolicyStatusApplyConfiguration) WithObservedGeneration(value int64) *ValidatingAdmissionPolicyStatusApplyConfiguration {
|
||||||
|
b.ObservedGeneration = &value
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithTypeChecking sets the TypeChecking 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 TypeChecking field is set to the value of the last call.
|
||||||
|
func (b *ValidatingAdmissionPolicyStatusApplyConfiguration) WithTypeChecking(value *TypeCheckingApplyConfiguration) *ValidatingAdmissionPolicyStatusApplyConfiguration {
|
||||||
|
b.TypeChecking = value
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithConditions adds the given value to the Conditions field in the declarative configuration
|
||||||
|
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
|
||||||
|
// If called multiple times, values provided by each call will be appended to the Conditions field.
|
||||||
|
func (b *ValidatingAdmissionPolicyStatusApplyConfiguration) WithConditions(values ...*v1.ConditionApplyConfiguration) *ValidatingAdmissionPolicyStatusApplyConfiguration {
|
||||||
|
for i := range values {
|
||||||
|
if values[i] == nil {
|
||||||
|
panic("nil value passed to WithConditions")
|
||||||
|
}
|
||||||
|
b.Conditions = append(b.Conditions, *values[i])
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
@ -236,6 +236,17 @@ var schemaYAML = typed.YAMLObject(`types:
|
|||||||
type:
|
type:
|
||||||
scalar: string
|
scalar: string
|
||||||
default: ""
|
default: ""
|
||||||
|
- name: io.k8s.api.admissionregistration.v1alpha1.ExpressionWarning
|
||||||
|
map:
|
||||||
|
fields:
|
||||||
|
- name: fieldRef
|
||||||
|
type:
|
||||||
|
scalar: string
|
||||||
|
default: ""
|
||||||
|
- name: warning
|
||||||
|
type:
|
||||||
|
scalar: string
|
||||||
|
default: ""
|
||||||
- name: io.k8s.api.admissionregistration.v1alpha1.MatchResources
|
- name: io.k8s.api.admissionregistration.v1alpha1.MatchResources
|
||||||
map:
|
map:
|
||||||
fields:
|
fields:
|
||||||
@ -318,6 +329,15 @@ var schemaYAML = typed.YAMLObject(`types:
|
|||||||
type:
|
type:
|
||||||
scalar: string
|
scalar: string
|
||||||
elementRelationship: atomic
|
elementRelationship: atomic
|
||||||
|
- name: io.k8s.api.admissionregistration.v1alpha1.TypeChecking
|
||||||
|
map:
|
||||||
|
fields:
|
||||||
|
- name: expressionWarnings
|
||||||
|
type:
|
||||||
|
list:
|
||||||
|
elementType:
|
||||||
|
namedType: io.k8s.api.admissionregistration.v1alpha1.ExpressionWarning
|
||||||
|
elementRelationship: atomic
|
||||||
- name: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy
|
- name: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy
|
||||||
map:
|
map:
|
||||||
fields:
|
fields:
|
||||||
@ -335,6 +355,10 @@ var schemaYAML = typed.YAMLObject(`types:
|
|||||||
type:
|
type:
|
||||||
namedType: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicySpec
|
namedType: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicySpec
|
||||||
default: {}
|
default: {}
|
||||||
|
- name: status
|
||||||
|
type:
|
||||||
|
namedType: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyStatus
|
||||||
|
default: {}
|
||||||
- name: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyBinding
|
- name: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyBinding
|
||||||
map:
|
map:
|
||||||
fields:
|
fields:
|
||||||
@ -394,6 +418,23 @@ var schemaYAML = typed.YAMLObject(`types:
|
|||||||
elementType:
|
elementType:
|
||||||
namedType: io.k8s.api.admissionregistration.v1alpha1.Validation
|
namedType: io.k8s.api.admissionregistration.v1alpha1.Validation
|
||||||
elementRelationship: atomic
|
elementRelationship: atomic
|
||||||
|
- name: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyStatus
|
||||||
|
map:
|
||||||
|
fields:
|
||||||
|
- name: conditions
|
||||||
|
type:
|
||||||
|
list:
|
||||||
|
elementType:
|
||||||
|
namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Condition
|
||||||
|
elementRelationship: associative
|
||||||
|
keys:
|
||||||
|
- type
|
||||||
|
- name: observedGeneration
|
||||||
|
type:
|
||||||
|
scalar: numeric
|
||||||
|
- name: typeChecking
|
||||||
|
type:
|
||||||
|
namedType: io.k8s.api.admissionregistration.v1alpha1.TypeChecking
|
||||||
- name: io.k8s.api.admissionregistration.v1alpha1.Validation
|
- name: io.k8s.api.admissionregistration.v1alpha1.Validation
|
||||||
map:
|
map:
|
||||||
fields:
|
fields:
|
||||||
|
@ -141,6 +141,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} {
|
|||||||
// Group=admissionregistration.k8s.io, Version=v1alpha1
|
// Group=admissionregistration.k8s.io, Version=v1alpha1
|
||||||
case v1alpha1.SchemeGroupVersion.WithKind("AuditAnnotation"):
|
case v1alpha1.SchemeGroupVersion.WithKind("AuditAnnotation"):
|
||||||
return &admissionregistrationv1alpha1.AuditAnnotationApplyConfiguration{}
|
return &admissionregistrationv1alpha1.AuditAnnotationApplyConfiguration{}
|
||||||
|
case v1alpha1.SchemeGroupVersion.WithKind("ExpressionWarning"):
|
||||||
|
return &admissionregistrationv1alpha1.ExpressionWarningApplyConfiguration{}
|
||||||
case v1alpha1.SchemeGroupVersion.WithKind("MatchResources"):
|
case v1alpha1.SchemeGroupVersion.WithKind("MatchResources"):
|
||||||
return &admissionregistrationv1alpha1.MatchResourcesApplyConfiguration{}
|
return &admissionregistrationv1alpha1.MatchResourcesApplyConfiguration{}
|
||||||
case v1alpha1.SchemeGroupVersion.WithKind("NamedRuleWithOperations"):
|
case v1alpha1.SchemeGroupVersion.WithKind("NamedRuleWithOperations"):
|
||||||
@ -149,6 +151,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} {
|
|||||||
return &admissionregistrationv1alpha1.ParamKindApplyConfiguration{}
|
return &admissionregistrationv1alpha1.ParamKindApplyConfiguration{}
|
||||||
case v1alpha1.SchemeGroupVersion.WithKind("ParamRef"):
|
case v1alpha1.SchemeGroupVersion.WithKind("ParamRef"):
|
||||||
return &admissionregistrationv1alpha1.ParamRefApplyConfiguration{}
|
return &admissionregistrationv1alpha1.ParamRefApplyConfiguration{}
|
||||||
|
case v1alpha1.SchemeGroupVersion.WithKind("TypeChecking"):
|
||||||
|
return &admissionregistrationv1alpha1.TypeCheckingApplyConfiguration{}
|
||||||
case v1alpha1.SchemeGroupVersion.WithKind("ValidatingAdmissionPolicy"):
|
case v1alpha1.SchemeGroupVersion.WithKind("ValidatingAdmissionPolicy"):
|
||||||
return &admissionregistrationv1alpha1.ValidatingAdmissionPolicyApplyConfiguration{}
|
return &admissionregistrationv1alpha1.ValidatingAdmissionPolicyApplyConfiguration{}
|
||||||
case v1alpha1.SchemeGroupVersion.WithKind("ValidatingAdmissionPolicyBinding"):
|
case v1alpha1.SchemeGroupVersion.WithKind("ValidatingAdmissionPolicyBinding"):
|
||||||
@ -157,6 +161,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} {
|
|||||||
return &admissionregistrationv1alpha1.ValidatingAdmissionPolicyBindingSpecApplyConfiguration{}
|
return &admissionregistrationv1alpha1.ValidatingAdmissionPolicyBindingSpecApplyConfiguration{}
|
||||||
case v1alpha1.SchemeGroupVersion.WithKind("ValidatingAdmissionPolicySpec"):
|
case v1alpha1.SchemeGroupVersion.WithKind("ValidatingAdmissionPolicySpec"):
|
||||||
return &admissionregistrationv1alpha1.ValidatingAdmissionPolicySpecApplyConfiguration{}
|
return &admissionregistrationv1alpha1.ValidatingAdmissionPolicySpecApplyConfiguration{}
|
||||||
|
case v1alpha1.SchemeGroupVersion.WithKind("ValidatingAdmissionPolicyStatus"):
|
||||||
|
return &admissionregistrationv1alpha1.ValidatingAdmissionPolicyStatusApplyConfiguration{}
|
||||||
case v1alpha1.SchemeGroupVersion.WithKind("Validation"):
|
case v1alpha1.SchemeGroupVersion.WithKind("Validation"):
|
||||||
return &admissionregistrationv1alpha1.ValidationApplyConfiguration{}
|
return &admissionregistrationv1alpha1.ValidationApplyConfiguration{}
|
||||||
|
|
||||||
|
@ -98,6 +98,17 @@ func (c *FakeValidatingAdmissionPolicies) Update(ctx context.Context, validating
|
|||||||
return obj.(*v1alpha1.ValidatingAdmissionPolicy), err
|
return obj.(*v1alpha1.ValidatingAdmissionPolicy), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateStatus was generated because the type contains a Status member.
|
||||||
|
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||||
|
func (c *FakeValidatingAdmissionPolicies) UpdateStatus(ctx context.Context, validatingAdmissionPolicy *v1alpha1.ValidatingAdmissionPolicy, opts v1.UpdateOptions) (*v1alpha1.ValidatingAdmissionPolicy, error) {
|
||||||
|
obj, err := c.Fake.
|
||||||
|
Invokes(testing.NewRootUpdateSubresourceAction(validatingadmissionpoliciesResource, "status", validatingAdmissionPolicy), &v1alpha1.ValidatingAdmissionPolicy{})
|
||||||
|
if obj == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return obj.(*v1alpha1.ValidatingAdmissionPolicy), err
|
||||||
|
}
|
||||||
|
|
||||||
// Delete takes name of the validatingAdmissionPolicy and deletes it. Returns an error if one occurs.
|
// Delete takes name of the validatingAdmissionPolicy and deletes it. Returns an error if one occurs.
|
||||||
func (c *FakeValidatingAdmissionPolicies) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
|
func (c *FakeValidatingAdmissionPolicies) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
|
||||||
_, err := c.Fake.
|
_, err := c.Fake.
|
||||||
@ -143,3 +154,25 @@ func (c *FakeValidatingAdmissionPolicies) Apply(ctx context.Context, validatingA
|
|||||||
}
|
}
|
||||||
return obj.(*v1alpha1.ValidatingAdmissionPolicy), err
|
return obj.(*v1alpha1.ValidatingAdmissionPolicy), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ApplyStatus was generated because the type contains a Status member.
|
||||||
|
// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus().
|
||||||
|
func (c *FakeValidatingAdmissionPolicies) ApplyStatus(ctx context.Context, validatingAdmissionPolicy *admissionregistrationv1alpha1.ValidatingAdmissionPolicyApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.ValidatingAdmissionPolicy, err error) {
|
||||||
|
if validatingAdmissionPolicy == nil {
|
||||||
|
return nil, fmt.Errorf("validatingAdmissionPolicy provided to Apply must not be nil")
|
||||||
|
}
|
||||||
|
data, err := json.Marshal(validatingAdmissionPolicy)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
name := validatingAdmissionPolicy.Name
|
||||||
|
if name == nil {
|
||||||
|
return nil, fmt.Errorf("validatingAdmissionPolicy.Name must be provided to Apply")
|
||||||
|
}
|
||||||
|
obj, err := c.Fake.
|
||||||
|
Invokes(testing.NewRootPatchSubresourceAction(validatingadmissionpoliciesResource, *name, types.ApplyPatchType, data, "status"), &v1alpha1.ValidatingAdmissionPolicy{})
|
||||||
|
if obj == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return obj.(*v1alpha1.ValidatingAdmissionPolicy), err
|
||||||
|
}
|
||||||
|
@ -43,6 +43,7 @@ type ValidatingAdmissionPoliciesGetter interface {
|
|||||||
type ValidatingAdmissionPolicyInterface interface {
|
type ValidatingAdmissionPolicyInterface interface {
|
||||||
Create(ctx context.Context, validatingAdmissionPolicy *v1alpha1.ValidatingAdmissionPolicy, opts v1.CreateOptions) (*v1alpha1.ValidatingAdmissionPolicy, error)
|
Create(ctx context.Context, validatingAdmissionPolicy *v1alpha1.ValidatingAdmissionPolicy, opts v1.CreateOptions) (*v1alpha1.ValidatingAdmissionPolicy, error)
|
||||||
Update(ctx context.Context, validatingAdmissionPolicy *v1alpha1.ValidatingAdmissionPolicy, opts v1.UpdateOptions) (*v1alpha1.ValidatingAdmissionPolicy, error)
|
Update(ctx context.Context, validatingAdmissionPolicy *v1alpha1.ValidatingAdmissionPolicy, opts v1.UpdateOptions) (*v1alpha1.ValidatingAdmissionPolicy, error)
|
||||||
|
UpdateStatus(ctx context.Context, validatingAdmissionPolicy *v1alpha1.ValidatingAdmissionPolicy, opts v1.UpdateOptions) (*v1alpha1.ValidatingAdmissionPolicy, error)
|
||||||
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
|
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
|
||||||
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
|
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
|
||||||
Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.ValidatingAdmissionPolicy, error)
|
Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.ValidatingAdmissionPolicy, error)
|
||||||
@ -50,6 +51,7 @@ type ValidatingAdmissionPolicyInterface interface {
|
|||||||
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
|
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
|
||||||
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ValidatingAdmissionPolicy, err error)
|
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ValidatingAdmissionPolicy, err error)
|
||||||
Apply(ctx context.Context, validatingAdmissionPolicy *admissionregistrationv1alpha1.ValidatingAdmissionPolicyApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.ValidatingAdmissionPolicy, err error)
|
Apply(ctx context.Context, validatingAdmissionPolicy *admissionregistrationv1alpha1.ValidatingAdmissionPolicyApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.ValidatingAdmissionPolicy, err error)
|
||||||
|
ApplyStatus(ctx context.Context, validatingAdmissionPolicy *admissionregistrationv1alpha1.ValidatingAdmissionPolicyApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.ValidatingAdmissionPolicy, err error)
|
||||||
ValidatingAdmissionPolicyExpansion
|
ValidatingAdmissionPolicyExpansion
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,6 +134,21 @@ func (c *validatingAdmissionPolicies) Update(ctx context.Context, validatingAdmi
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateStatus was generated because the type contains a Status member.
|
||||||
|
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||||
|
func (c *validatingAdmissionPolicies) UpdateStatus(ctx context.Context, validatingAdmissionPolicy *v1alpha1.ValidatingAdmissionPolicy, opts v1.UpdateOptions) (result *v1alpha1.ValidatingAdmissionPolicy, err error) {
|
||||||
|
result = &v1alpha1.ValidatingAdmissionPolicy{}
|
||||||
|
err = c.client.Put().
|
||||||
|
Resource("validatingadmissionpolicies").
|
||||||
|
Name(validatingAdmissionPolicy.Name).
|
||||||
|
SubResource("status").
|
||||||
|
VersionedParams(&opts, scheme.ParameterCodec).
|
||||||
|
Body(validatingAdmissionPolicy).
|
||||||
|
Do(ctx).
|
||||||
|
Into(result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Delete takes name of the validatingAdmissionPolicy and deletes it. Returns an error if one occurs.
|
// Delete takes name of the validatingAdmissionPolicy and deletes it. Returns an error if one occurs.
|
||||||
func (c *validatingAdmissionPolicies) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
|
func (c *validatingAdmissionPolicies) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
|
||||||
return c.client.Delete().
|
return c.client.Delete().
|
||||||
@ -195,3 +212,32 @@ func (c *validatingAdmissionPolicies) Apply(ctx context.Context, validatingAdmis
|
|||||||
Into(result)
|
Into(result)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ApplyStatus was generated because the type contains a Status member.
|
||||||
|
// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus().
|
||||||
|
func (c *validatingAdmissionPolicies) ApplyStatus(ctx context.Context, validatingAdmissionPolicy *admissionregistrationv1alpha1.ValidatingAdmissionPolicyApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.ValidatingAdmissionPolicy, err error) {
|
||||||
|
if validatingAdmissionPolicy == nil {
|
||||||
|
return nil, fmt.Errorf("validatingAdmissionPolicy provided to Apply must not be nil")
|
||||||
|
}
|
||||||
|
patchOpts := opts.ToPatchOptions()
|
||||||
|
data, err := json.Marshal(validatingAdmissionPolicy)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
name := validatingAdmissionPolicy.Name
|
||||||
|
if name == nil {
|
||||||
|
return nil, fmt.Errorf("validatingAdmissionPolicy.Name must be provided to Apply")
|
||||||
|
}
|
||||||
|
|
||||||
|
result = &v1alpha1.ValidatingAdmissionPolicy{}
|
||||||
|
err = c.client.Patch(types.ApplyPatchType).
|
||||||
|
Resource("validatingadmissionpolicies").
|
||||||
|
Name(*name).
|
||||||
|
SubResource("status").
|
||||||
|
VersionedParams(&patchOpts, scheme.ParameterCodec).
|
||||||
|
Body(data).
|
||||||
|
Do(ctx).
|
||||||
|
Into(result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@ -24,6 +24,7 @@ require (
|
|||||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||||
github.com/NYTimes/gziphandler v1.1.1 // indirect
|
github.com/NYTimes/gziphandler v1.1.1 // indirect
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect
|
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect
|
||||||
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
|
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
|
||||||
@ -56,6 +57,7 @@ require (
|
|||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect
|
||||||
|
github.com/mitchellh/mapstructure v1.4.1 // indirect
|
||||||
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect
|
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
4
staging/src/k8s.io/cloud-provider/go.sum
generated
4
staging/src/k8s.io/cloud-provider/go.sum
generated
@ -48,6 +48,8 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5
|
|||||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves=
|
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves=
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
|
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
|
||||||
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
|
||||||
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
@ -250,6 +252,8 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
|
|||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM=
|
github.com/matttproud/golang_protobuf_extensions v1.0.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||||
|
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
|
||||||
|
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA=
|
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA=
|
||||||
github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
@ -20,6 +20,7 @@ require (
|
|||||||
require (
|
require (
|
||||||
github.com/NYTimes/gziphandler v1.1.1 // indirect
|
github.com/NYTimes/gziphandler v1.1.1 // indirect
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect
|
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect
|
||||||
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
|
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
|
||||||
@ -52,6 +53,7 @@ require (
|
|||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect
|
||||||
|
github.com/mitchellh/mapstructure v1.4.1 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
|
4
staging/src/k8s.io/controller-manager/go.sum
generated
4
staging/src/k8s.io/controller-manager/go.sum
generated
@ -45,6 +45,8 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5
|
|||||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves=
|
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves=
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
|
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
|
||||||
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
|
||||||
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
@ -245,6 +247,8 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
|
|||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM=
|
github.com/matttproud/golang_protobuf_extensions v1.0.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||||
|
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
|
||||||
|
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
@ -28,6 +28,7 @@ require (
|
|||||||
require (
|
require (
|
||||||
github.com/NYTimes/gziphandler v1.1.1 // indirect
|
github.com/NYTimes/gziphandler v1.1.1 // indirect
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect
|
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect
|
||||||
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
|
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
|
||||||
@ -56,6 +57,7 @@ require (
|
|||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect
|
||||||
|
github.com/mitchellh/mapstructure v1.4.1 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
|
4
staging/src/k8s.io/kube-aggregator/go.sum
generated
4
staging/src/k8s.io/kube-aggregator/go.sum
generated
@ -46,6 +46,8 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5
|
|||||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves=
|
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves=
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
|
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
|
||||||
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
|
||||||
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
@ -247,6 +249,8 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
|
|||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM=
|
github.com/matttproud/golang_protobuf_extensions v1.0.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||||
|
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
|
||||||
|
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
@ -23,6 +23,7 @@ require (
|
|||||||
require (
|
require (
|
||||||
github.com/NYTimes/gziphandler v1.1.1 // indirect
|
github.com/NYTimes/gziphandler v1.1.1 // indirect
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect
|
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect
|
||||||
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
|
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||||
@ -54,6 +55,7 @@ require (
|
|||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect
|
||||||
|
github.com/mitchellh/mapstructure v1.4.1 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
|
4
staging/src/k8s.io/pod-security-admission/go.sum
generated
4
staging/src/k8s.io/pod-security-admission/go.sum
generated
@ -46,6 +46,8 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5
|
|||||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves=
|
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves=
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
|
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
|
||||||
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
|
||||||
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
@ -247,6 +249,8 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
|
|||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM=
|
github.com/matttproud/golang_protobuf_extensions v1.0.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||||
|
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
|
||||||
|
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
@ -20,6 +20,7 @@ require (
|
|||||||
require (
|
require (
|
||||||
github.com/NYTimes/gziphandler v1.1.1 // indirect
|
github.com/NYTimes/gziphandler v1.1.1 // indirect
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect
|
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect
|
||||||
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
|
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
|
||||||
@ -51,6 +52,7 @@ require (
|
|||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect
|
||||||
|
github.com/mitchellh/mapstructure v1.4.1 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
|
4
staging/src/k8s.io/sample-apiserver/go.sum
generated
4
staging/src/k8s.io/sample-apiserver/go.sum
generated
@ -46,6 +46,8 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5
|
|||||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves=
|
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves=
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
|
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
|
||||||
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
|
||||||
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
@ -247,6 +249,8 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
|
|||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM=
|
github.com/matttproud/golang_protobuf_extensions v1.0.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||||
|
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
|
||||||
|
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
@ -138,12 +138,13 @@ var (
|
|||||||
// admissionExemptResources lists objects which are exempt from admission validation/mutation,
|
// admissionExemptResources lists objects which are exempt from admission validation/mutation,
|
||||||
// only resources exempted from admission processing by API server should be listed here.
|
// only resources exempted from admission processing by API server should be listed here.
|
||||||
admissionExemptResources = map[schema.GroupVersionResource]bool{
|
admissionExemptResources = map[schema.GroupVersionResource]bool{
|
||||||
gvr("admissionregistration.k8s.io", "v1beta1", "mutatingwebhookconfigurations"): true,
|
gvr("admissionregistration.k8s.io", "v1beta1", "mutatingwebhookconfigurations"): true,
|
||||||
gvr("admissionregistration.k8s.io", "v1beta1", "validatingwebhookconfigurations"): true,
|
gvr("admissionregistration.k8s.io", "v1beta1", "validatingwebhookconfigurations"): true,
|
||||||
gvr("admissionregistration.k8s.io", "v1", "mutatingwebhookconfigurations"): true,
|
gvr("admissionregistration.k8s.io", "v1", "mutatingwebhookconfigurations"): true,
|
||||||
gvr("admissionregistration.k8s.io", "v1", "validatingwebhookconfigurations"): true,
|
gvr("admissionregistration.k8s.io", "v1", "validatingwebhookconfigurations"): true,
|
||||||
gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicies"): true,
|
gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicies"): true,
|
||||||
gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicybindings"): true,
|
gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicies/status"): true,
|
||||||
|
gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicybindings"): true,
|
||||||
}
|
}
|
||||||
|
|
||||||
parentResources = map[schema.GroupVersionResource]schema.GroupVersionResource{
|
parentResources = map[schema.GroupVersionResource]schema.GroupVersionResource{
|
||||||
|
@ -67,6 +67,8 @@ var resetFieldsStatusData = map[schema.GroupVersionResource]string{
|
|||||||
gvr("resource.k8s.io", "v1alpha1", "podschedulings"): `{"status": {"resourceClaims": [{"name": "my-claim", "unsuitableNodes": ["node2"]}]}}`, // Not really a conflict with status_test.go: Apply just stores both nodes. Conflict testing therefore gets disabled for podschedulings.
|
gvr("resource.k8s.io", "v1alpha1", "podschedulings"): `{"status": {"resourceClaims": [{"name": "my-claim", "unsuitableNodes": ["node2"]}]}}`, // Not really a conflict with status_test.go: Apply just stores both nodes. Conflict testing therefore gets disabled for podschedulings.
|
||||||
gvr("resource.k8s.io", "v1alpha1", "resourceclaims"): `{"status": {"driverName": "other.example.com"}}`,
|
gvr("resource.k8s.io", "v1alpha1", "resourceclaims"): `{"status": {"driverName": "other.example.com"}}`,
|
||||||
gvr("internal.apiserver.k8s.io", "v1alpha1", "storageversions"): `{"status": {"commonEncodingVersion":"v1","storageVersions":[{"apiServerID":"1","decodableVersions":["v1","v2"],"encodingVersion":"v1"}],"conditions":[{"type":"AllEncodingVersionsEqual","status":"False","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"allEncodingVersionsEqual","message":"all encoding versions are set to v1"}]}}`,
|
gvr("internal.apiserver.k8s.io", "v1alpha1", "storageversions"): `{"status": {"commonEncodingVersion":"v1","storageVersions":[{"apiServerID":"1","decodableVersions":["v1","v2"],"encodingVersion":"v1"}],"conditions":[{"type":"AllEncodingVersionsEqual","status":"False","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"allEncodingVersionsEqual","message":"all encoding versions are set to v1"}]}}`,
|
||||||
|
// standard for []metav1.Condition
|
||||||
|
gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicies"): `{"status": {"conditions":[{"type":"Accepted","status":"True","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"RuleApplied","message":"Rule was applied"}]}}`,
|
||||||
}
|
}
|
||||||
|
|
||||||
// resetFieldsStatusDefault conflicts with statusDefault
|
// resetFieldsStatusDefault conflicts with statusDefault
|
||||||
@ -151,6 +153,7 @@ var resetFieldsSpecData = map[schema.GroupVersionResource]string{
|
|||||||
gvr("resource.k8s.io", "v1alpha1", "resourceclaims"): `{"spec": {"resourceClassName": "class2name"}}`, // ResourceClassName is immutable, but that doesn't matter for the test.
|
gvr("resource.k8s.io", "v1alpha1", "resourceclaims"): `{"spec": {"resourceClassName": "class2name"}}`, // ResourceClassName is immutable, but that doesn't matter for the test.
|
||||||
gvr("resource.k8s.io", "v1alpha1", "resourceclaimtemplates"): `{"spec": {"spec": {"resourceClassName": "class2name"}}}`,
|
gvr("resource.k8s.io", "v1alpha1", "resourceclaimtemplates"): `{"spec": {"spec": {"resourceClassName": "class2name"}}}`,
|
||||||
gvr("internal.apiserver.k8s.io", "v1alpha1", "storageversions"): `{}`,
|
gvr("internal.apiserver.k8s.io", "v1alpha1", "storageversions"): `{}`,
|
||||||
|
gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicies"): `{"metadata": {"labels": {"a":"c"}}, "spec": {"paramKind": {"apiVersion": "apps/v1", "kind": "Deployment"}}}`,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestResetFields makes sure that fieldManager does not own fields reset by the storage strategy.
|
// TestResetFields makes sure that fieldManager does not own fields reset by the storage strategy.
|
||||||
|
@ -57,6 +57,8 @@ var statusData = map[schema.GroupVersionResource]string{
|
|||||||
gvr("resource.k8s.io", "v1alpha1", "podschedulings"): `{"status": {"resourceClaims": [{"name": "my-claim", "unsuitableNodes": ["node1"]}]}}`,
|
gvr("resource.k8s.io", "v1alpha1", "podschedulings"): `{"status": {"resourceClaims": [{"name": "my-claim", "unsuitableNodes": ["node1"]}]}}`,
|
||||||
gvr("resource.k8s.io", "v1alpha1", "resourceclaims"): `{"status": {"driverName": "example.com"}}`,
|
gvr("resource.k8s.io", "v1alpha1", "resourceclaims"): `{"status": {"driverName": "example.com"}}`,
|
||||||
gvr("internal.apiserver.k8s.io", "v1alpha1", "storageversions"): `{"status": {"commonEncodingVersion":"v1","storageVersions":[{"apiServerID":"1","decodableVersions":["v1","v2"],"encodingVersion":"v1"}],"conditions":[{"type":"AllEncodingVersionsEqual","status":"True","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"allEncodingVersionsEqual","message":"all encoding versions are set to v1"}]}}`,
|
gvr("internal.apiserver.k8s.io", "v1alpha1", "storageversions"): `{"status": {"commonEncodingVersion":"v1","storageVersions":[{"apiServerID":"1","decodableVersions":["v1","v2"],"encodingVersion":"v1"}],"conditions":[{"type":"AllEncodingVersionsEqual","status":"True","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"allEncodingVersionsEqual","message":"all encoding versions are set to v1"}]}}`,
|
||||||
|
// standard for []metav1.Condition
|
||||||
|
gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicies"): `{"status": {"conditions":[{"type":"Accepted","status":"False","lastTransitionTime":"2020-01-01T00:00:00Z","reason":"RuleApplied","message":"Rule was applied"}]}}`,
|
||||||
}
|
}
|
||||||
|
|
||||||
const statusDefault = `{"status": {"conditions": [{"type": "MyStatus", "status":"True"}]}}`
|
const statusDefault = `{"status": {"conditions": [{"type": "MyStatus", "status":"True"}]}}`
|
||||||
|
@ -751,10 +751,13 @@ func Test_PolicyExemption(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// validate that operations to ValidatingAdmissionPolicy are exempt from an existing policy that catches all resources
|
// validate that operations to ValidatingAdmissionPolicy are exempt from an existing policy that catches all resources
|
||||||
policyCopy := policy.DeepCopy()
|
policy, err = client.AdmissionregistrationV1alpha1().ValidatingAdmissionPolicies().Get(context.TODO(), policy.Name, metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
ignoreFailurePolicy := admissionregistrationv1alpha1.Ignore
|
ignoreFailurePolicy := admissionregistrationv1alpha1.Ignore
|
||||||
policyCopy.Spec.FailurePolicy = &ignoreFailurePolicy
|
policy.Spec.FailurePolicy = &ignoreFailurePolicy
|
||||||
_, err = client.AdmissionregistrationV1alpha1().ValidatingAdmissionPolicies().Update(context.TODO(), policyCopy, metav1.UpdateOptions{})
|
_, err = client.AdmissionregistrationV1alpha1().ValidatingAdmissionPolicies().Update(context.TODO(), policy, metav1.UpdateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -866,9 +869,12 @@ func Test_ValidatingAdmissionPolicy_UpdateParamKind(t *testing.T) {
|
|||||||
APIVersion: "v1",
|
APIVersion: "v1",
|
||||||
Kind: "Secret",
|
Kind: "Secret",
|
||||||
}
|
}
|
||||||
policyCopy := policy.DeepCopy()
|
policy, err = client.AdmissionregistrationV1alpha1().ValidatingAdmissionPolicies().Get(context.TODO(), policy.Name, metav1.GetOptions{})
|
||||||
policyCopy.Spec.ParamKind = paramKind
|
if err != nil {
|
||||||
_, err = client.AdmissionregistrationV1alpha1().ValidatingAdmissionPolicies().Update(context.TODO(), policyCopy, metav1.UpdateOptions{})
|
t.Error(err)
|
||||||
|
}
|
||||||
|
policy.Spec.ParamKind = paramKind
|
||||||
|
_, err = client.AdmissionregistrationV1alpha1().ValidatingAdmissionPolicies().Update(context.TODO(), policy, metav1.UpdateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -2611,6 +2617,26 @@ func withPolicyExistsLabels(labels []string, policy *admissionregistrationv1alph
|
|||||||
return policy
|
return policy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func withGVRMatch(groups []string, versions []string, resources []string, policy *admissionregistrationv1alpha1.ValidatingAdmissionPolicy) *admissionregistrationv1alpha1.ValidatingAdmissionPolicy {
|
||||||
|
policy.Spec.MatchConstraints = &admissionregistrationv1alpha1.MatchResources{
|
||||||
|
ResourceRules: []admissionregistrationv1alpha1.NamedRuleWithOperations{
|
||||||
|
{
|
||||||
|
RuleWithOperations: admissionregistrationv1alpha1.RuleWithOperations{
|
||||||
|
Operations: []admissionregistrationv1.OperationType{
|
||||||
|
"*",
|
||||||
|
},
|
||||||
|
Rule: admissionregistrationv1.Rule{
|
||||||
|
APIGroups: groups,
|
||||||
|
APIVersions: versions,
|
||||||
|
Resources: resources,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return policy
|
||||||
|
}
|
||||||
|
|
||||||
func withValidations(validations []admissionregistrationv1alpha1.Validation, policy *admissionregistrationv1alpha1.ValidatingAdmissionPolicy) *admissionregistrationv1alpha1.ValidatingAdmissionPolicy {
|
func withValidations(validations []admissionregistrationv1alpha1.Validation, policy *admissionregistrationv1alpha1.ValidatingAdmissionPolicy) *admissionregistrationv1alpha1.ValidatingAdmissionPolicy {
|
||||||
policy.Spec.Validations = validations
|
policy.Spec.Validations = validations
|
||||||
return policy
|
return policy
|
||||||
@ -2885,3 +2911,114 @@ rules:
|
|||||||
resources: ["configmaps"]
|
resources: ["configmaps"]
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestValidatingAdmissionPolicyTypeChecking(t *testing.T) {
|
||||||
|
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, genericfeatures.ValidatingAdmissionPolicy, true)()
|
||||||
|
server, err := apiservertesting.StartTestServer(t, nil, []string{
|
||||||
|
"--enable-admission-plugins", "ValidatingAdmissionPolicy",
|
||||||
|
}, framework.SharedEtcd())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer server.TearDownFn()
|
||||||
|
|
||||||
|
config := server.ClientConfig
|
||||||
|
|
||||||
|
client, err := clientset.NewForConfig(config)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for _, tc := range []struct {
|
||||||
|
name string
|
||||||
|
policy *admissionregistrationv1alpha1.ValidatingAdmissionPolicy
|
||||||
|
assertFieldRef func(warnings []admissionregistrationv1alpha1.ExpressionWarning, t *testing.T) // warning.fieldRef
|
||||||
|
assertWarnings func(warnings []admissionregistrationv1alpha1.ExpressionWarning, t *testing.T) // warning.warning
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "deployment with correct expression",
|
||||||
|
policy: withGVRMatch([]string{"apps"}, []string{"v1"}, []string{"deployments"}, withValidations([]admissionregistrationv1alpha1.Validation{
|
||||||
|
{
|
||||||
|
Expression: "object.spec.replicas > 1",
|
||||||
|
},
|
||||||
|
}, makePolicy("replicated-deployment"))),
|
||||||
|
assertFieldRef: toHasLengthOf(0),
|
||||||
|
assertWarnings: toHasLengthOf(0),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "deployment with type confusion",
|
||||||
|
policy: withGVRMatch([]string{"apps"}, []string{"v1"}, []string{"deployments"}, withValidations([]admissionregistrationv1alpha1.Validation{
|
||||||
|
{
|
||||||
|
Expression: "object.spec.replicas < 100", // this one passes
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Expression: "object.spec.replicas > '1'", // '1' should be int
|
||||||
|
},
|
||||||
|
}, makePolicy("confused-deployment"))),
|
||||||
|
assertFieldRef: toBe("spec.validations[1].expression"),
|
||||||
|
assertWarnings: toHasSubstring(`found no matching overload for '_>_' applied to '(int, string)'`),
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
policy, err := client.AdmissionregistrationV1alpha1().ValidatingAdmissionPolicies().Create(ctx, tc.policy, metav1.CreateOptions{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer client.AdmissionregistrationV1alpha1().ValidatingAdmissionPolicies().Delete(context.Background(), policy.Name, metav1.DeleteOptions{})
|
||||||
|
err = wait.PollImmediateWithContext(ctx, time.Second, time.Minute, func(ctx context.Context) (done bool, err error) {
|
||||||
|
name := policy.Name
|
||||||
|
// wait until the typeChecking is set, which means the type checking
|
||||||
|
// is complete.
|
||||||
|
updated, err := client.AdmissionregistrationV1alpha1().ValidatingAdmissionPolicies().Get(ctx, name, metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if updated.Status.TypeChecking != nil {
|
||||||
|
policy = updated
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
tc.assertFieldRef(policy.Status.TypeChecking.ExpressionWarnings, t)
|
||||||
|
tc.assertWarnings(policy.Status.TypeChecking.ExpressionWarnings, t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toBe(expected ...string) func(warnings []admissionregistrationv1alpha1.ExpressionWarning, t *testing.T) {
|
||||||
|
return func(warnings []admissionregistrationv1alpha1.ExpressionWarning, t *testing.T) {
|
||||||
|
if len(expected) != len(warnings) {
|
||||||
|
t.Fatalf("mismatched length, expect %d, got %d", len(expected), len(warnings))
|
||||||
|
}
|
||||||
|
for i := range expected {
|
||||||
|
if expected[i] != warnings[i].FieldRef {
|
||||||
|
t.Errorf("expected %q but got %q", expected[i], warnings[i].FieldRef)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toHasSubstring(substrings ...string) func(warnings []admissionregistrationv1alpha1.ExpressionWarning, t *testing.T) {
|
||||||
|
return func(warnings []admissionregistrationv1alpha1.ExpressionWarning, t *testing.T) {
|
||||||
|
if len(substrings) != len(warnings) {
|
||||||
|
t.Fatalf("mismatched length, expect %d, got %d", len(substrings), len(warnings))
|
||||||
|
}
|
||||||
|
for i := range substrings {
|
||||||
|
if !strings.Contains(warnings[i].Warning, substrings[i]) {
|
||||||
|
t.Errorf("missing expected substring %q in %v", substrings[i], warnings[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toHasLengthOf(n int) func(warnings []admissionregistrationv1alpha1.ExpressionWarning, t *testing.T) {
|
||||||
|
return func(warnings []admissionregistrationv1alpha1.ExpressionWarning, t *testing.T) {
|
||||||
|
if n != len(warnings) {
|
||||||
|
t.Fatalf("mismatched length, expect %d, got %d", n, len(warnings))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user