diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index 0f638e05ab4..3acd35cb01f 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -366,6 +366,24 @@ ], "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": { "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": { @@ -482,6 +500,20 @@ "type": "object", "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": { "description": "ValidatingAdmissionPolicy describes the definition of an admission validation policy that accepts or rejects an object without changing it.", "properties": { @@ -500,6 +532,10 @@ "spec": { "$ref": "#/definitions/io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicySpec", "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", @@ -664,6 +700,32 @@ }, "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": { "description": "Validation specifies the CEL expression which is used to apply the validation.", "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": { "delete": { "consumes": [ diff --git a/api/openapi-spec/v3/apis__admissionregistration.k8s.io__v1alpha1_openapi.json b/api/openapi-spec/v3/apis__admissionregistration.k8s.io__v1alpha1_openapi.json index 2fca3282c34..d22f4b77398 100644 --- a/api/openapi-spec/v3/apis__admissionregistration.k8s.io__v1alpha1_openapi.json +++ b/api/openapi-spec/v3/apis__admissionregistration.k8s.io__v1alpha1_openapi.json @@ -21,6 +21,26 @@ ], "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": { "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": { @@ -160,6 +180,25 @@ "type": "object", "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": { "description": "ValidatingAdmissionPolicy describes the definition of an admission validation policy that accepts or rejects an object without changing it.", "properties": { @@ -188,6 +227,15 @@ ], "default": {}, "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", @@ -409,6 +457,41 @@ }, "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": { "description": "Validation specifies the CEL expression which is used to apply the validation.", "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": { "description": "DeleteOptions may be provided when deleting an API object.", "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": { "delete": { "description": "delete collection of ValidatingAdmissionPolicyBinding", diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index 63cb80fdabb..a410b61ede8 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -40,6 +40,7 @@ import ( "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/authorization/authorizer" + "k8s.io/apiserver/pkg/cel/openapi/resolver" "k8s.io/apiserver/pkg/endpoints/discovery/aggregated" genericapifilters "k8s.io/apiserver/pkg/endpoints/filters" openapinamer "k8s.io/apiserver/pkg/endpoints/openapi" @@ -56,6 +57,7 @@ import ( "k8s.io/apiserver/pkg/util/webhook" clientgoinformers "k8s.io/client-go/informers" clientgoclientset "k8s.io/client-go/kubernetes" + k8sscheme "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" "k8s.io/client-go/util/keyutil" cliflag "k8s.io/component-base/cli/flag" @@ -452,7 +454,8 @@ func buildGenericConfig( CloudConfigFile: s.CloudProvider.CloudConfigFile, } 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 { lastErr = fmt.Errorf("failed to create admission plugin initializer: %v", err) return diff --git a/pkg/apis/admissionregistration/types.go b/pkg/apis/admissionregistration/types.go index 851f9206aa3..9288057ef01 100644 --- a/pkg/apis/admissionregistration/types.go +++ b/pkg/apis/admissionregistration/types.go @@ -123,6 +123,52 @@ type ValidatingAdmissionPolicy struct { metav1.ObjectMeta // Specification of the desired behavior of the ValidatingAdmissionPolicy. Spec ValidatingAdmissionPolicySpec + // The status of the ValidatingAdmissionPolicy, including warnings that are useful to determine if the policy + // behaves in the expected way. + // Populated by the system. + // Read-only. + // +optional + Status ValidatingAdmissionPolicyStatus +} + +// ValidatingAdmissionPolicyStatus represents the status of an admission validation policy. +type ValidatingAdmissionPolicyStatus struct { + // The generation observed by the controller. + // +optional + ObservedGeneration int64 + // The results of type checking for each expression. + // Presence of this field indicates the completion of the type checking. + // +optional + TypeChecking *TypeChecking + // The conditions represent the latest available observations of a policy's current state. + // +optional + // +listType=map + // +listMapKey=type + Conditions []metav1.Condition +} + +// ValidatingAdmissionPolicyConditionType is the condition type of admission validation policy. +type ValidatingAdmissionPolicyConditionType string + +// TypeChecking contains results of type checking the expressions in the +// ValidatingAdmissionPolicy +type TypeChecking struct { + // The type checking warnings for each expression. + // +optional + // +listType=atomic + ExpressionWarnings []ExpressionWarning +} + +// ExpressionWarning is a warning information that targets a specific expression. +type ExpressionWarning struct { + // The path to the field that refers the expression. + // For example, the reference to the expression of the first item of + // validations is "spec.validations[0].expression" + FieldRef string + // The content of type checking information in a human-readable form. + // Each line of the warning contains the type that the expression is checked + // against, followed by the type check error from the compiler. + Warning string } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/apis/admissionregistration/v1alpha1/zz_generated.conversion.go b/pkg/apis/admissionregistration/v1alpha1/zz_generated.conversion.go index 5317f448295..c90b03ac40d 100644 --- a/pkg/apis/admissionregistration/v1alpha1/zz_generated.conversion.go +++ b/pkg/apis/admissionregistration/v1alpha1/zz_generated.conversion.go @@ -49,6 +49,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*v1alpha1.ExpressionWarning)(nil), (*admissionregistration.ExpressionWarning)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_ExpressionWarning_To_admissionregistration_ExpressionWarning(a.(*v1alpha1.ExpressionWarning), b.(*admissionregistration.ExpressionWarning), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*admissionregistration.ExpressionWarning)(nil), (*v1alpha1.ExpressionWarning)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_admissionregistration_ExpressionWarning_To_v1alpha1_ExpressionWarning(a.(*admissionregistration.ExpressionWarning), b.(*v1alpha1.ExpressionWarning), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*v1alpha1.MatchResources)(nil), (*admissionregistration.MatchResources)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha1_MatchResources_To_admissionregistration_MatchResources(a.(*v1alpha1.MatchResources), b.(*admissionregistration.MatchResources), scope) }); err != nil { @@ -89,6 +99,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*v1alpha1.TypeChecking)(nil), (*admissionregistration.TypeChecking)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_TypeChecking_To_admissionregistration_TypeChecking(a.(*v1alpha1.TypeChecking), b.(*admissionregistration.TypeChecking), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*admissionregistration.TypeChecking)(nil), (*v1alpha1.TypeChecking)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_admissionregistration_TypeChecking_To_v1alpha1_TypeChecking(a.(*admissionregistration.TypeChecking), b.(*v1alpha1.TypeChecking), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*v1alpha1.ValidatingAdmissionPolicy)(nil), (*admissionregistration.ValidatingAdmissionPolicy)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha1_ValidatingAdmissionPolicy_To_admissionregistration_ValidatingAdmissionPolicy(a.(*v1alpha1.ValidatingAdmissionPolicy), b.(*admissionregistration.ValidatingAdmissionPolicy), scope) }); err != nil { @@ -149,6 +169,16 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddGeneratedConversionFunc((*v1alpha1.ValidatingAdmissionPolicyStatus)(nil), (*admissionregistration.ValidatingAdmissionPolicyStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_ValidatingAdmissionPolicyStatus_To_admissionregistration_ValidatingAdmissionPolicyStatus(a.(*v1alpha1.ValidatingAdmissionPolicyStatus), b.(*admissionregistration.ValidatingAdmissionPolicyStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*admissionregistration.ValidatingAdmissionPolicyStatus)(nil), (*v1alpha1.ValidatingAdmissionPolicyStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_admissionregistration_ValidatingAdmissionPolicyStatus_To_v1alpha1_ValidatingAdmissionPolicyStatus(a.(*admissionregistration.ValidatingAdmissionPolicyStatus), b.(*v1alpha1.ValidatingAdmissionPolicyStatus), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*v1alpha1.Validation)(nil), (*admissionregistration.Validation)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha1_Validation_To_admissionregistration_Validation(a.(*v1alpha1.Validation), b.(*admissionregistration.Validation), scope) }); err != nil { @@ -184,6 +214,28 @@ func Convert_admissionregistration_AuditAnnotation_To_v1alpha1_AuditAnnotation(i return autoConvert_admissionregistration_AuditAnnotation_To_v1alpha1_AuditAnnotation(in, out, s) } +func autoConvert_v1alpha1_ExpressionWarning_To_admissionregistration_ExpressionWarning(in *v1alpha1.ExpressionWarning, out *admissionregistration.ExpressionWarning, s conversion.Scope) error { + out.FieldRef = in.FieldRef + out.Warning = in.Warning + return nil +} + +// Convert_v1alpha1_ExpressionWarning_To_admissionregistration_ExpressionWarning is an autogenerated conversion function. +func Convert_v1alpha1_ExpressionWarning_To_admissionregistration_ExpressionWarning(in *v1alpha1.ExpressionWarning, out *admissionregistration.ExpressionWarning, s conversion.Scope) error { + return autoConvert_v1alpha1_ExpressionWarning_To_admissionregistration_ExpressionWarning(in, out, s) +} + +func autoConvert_admissionregistration_ExpressionWarning_To_v1alpha1_ExpressionWarning(in *admissionregistration.ExpressionWarning, out *v1alpha1.ExpressionWarning, s conversion.Scope) error { + out.FieldRef = in.FieldRef + out.Warning = in.Warning + return nil +} + +// Convert_admissionregistration_ExpressionWarning_To_v1alpha1_ExpressionWarning is an autogenerated conversion function. +func Convert_admissionregistration_ExpressionWarning_To_v1alpha1_ExpressionWarning(in *admissionregistration.ExpressionWarning, out *v1alpha1.ExpressionWarning, s conversion.Scope) error { + return autoConvert_admissionregistration_ExpressionWarning_To_v1alpha1_ExpressionWarning(in, out, s) +} + func autoConvert_v1alpha1_MatchResources_To_admissionregistration_MatchResources(in *v1alpha1.MatchResources, out *admissionregistration.MatchResources, s conversion.Scope) error { out.NamespaceSelector = (*v1.LabelSelector)(unsafe.Pointer(in.NamespaceSelector)) out.ObjectSelector = (*v1.LabelSelector)(unsafe.Pointer(in.ObjectSelector)) @@ -322,11 +374,34 @@ func Convert_admissionregistration_ParamRef_To_v1alpha1_ParamRef(in *admissionre return autoConvert_admissionregistration_ParamRef_To_v1alpha1_ParamRef(in, out, s) } +func autoConvert_v1alpha1_TypeChecking_To_admissionregistration_TypeChecking(in *v1alpha1.TypeChecking, out *admissionregistration.TypeChecking, s conversion.Scope) error { + out.ExpressionWarnings = *(*[]admissionregistration.ExpressionWarning)(unsafe.Pointer(&in.ExpressionWarnings)) + return nil +} + +// Convert_v1alpha1_TypeChecking_To_admissionregistration_TypeChecking is an autogenerated conversion function. +func Convert_v1alpha1_TypeChecking_To_admissionregistration_TypeChecking(in *v1alpha1.TypeChecking, out *admissionregistration.TypeChecking, s conversion.Scope) error { + return autoConvert_v1alpha1_TypeChecking_To_admissionregistration_TypeChecking(in, out, s) +} + +func autoConvert_admissionregistration_TypeChecking_To_v1alpha1_TypeChecking(in *admissionregistration.TypeChecking, out *v1alpha1.TypeChecking, s conversion.Scope) error { + out.ExpressionWarnings = *(*[]v1alpha1.ExpressionWarning)(unsafe.Pointer(&in.ExpressionWarnings)) + return nil +} + +// Convert_admissionregistration_TypeChecking_To_v1alpha1_TypeChecking is an autogenerated conversion function. +func Convert_admissionregistration_TypeChecking_To_v1alpha1_TypeChecking(in *admissionregistration.TypeChecking, out *v1alpha1.TypeChecking, s conversion.Scope) error { + return autoConvert_admissionregistration_TypeChecking_To_v1alpha1_TypeChecking(in, out, s) +} + func autoConvert_v1alpha1_ValidatingAdmissionPolicy_To_admissionregistration_ValidatingAdmissionPolicy(in *v1alpha1.ValidatingAdmissionPolicy, out *admissionregistration.ValidatingAdmissionPolicy, s conversion.Scope) error { out.ObjectMeta = in.ObjectMeta if err := Convert_v1alpha1_ValidatingAdmissionPolicySpec_To_admissionregistration_ValidatingAdmissionPolicySpec(&in.Spec, &out.Spec, s); err != nil { return err } + if err := Convert_v1alpha1_ValidatingAdmissionPolicyStatus_To_admissionregistration_ValidatingAdmissionPolicyStatus(&in.Status, &out.Status, s); err != nil { + return err + } return nil } @@ -340,6 +415,9 @@ func autoConvert_admissionregistration_ValidatingAdmissionPolicy_To_v1alpha1_Val if err := Convert_admissionregistration_ValidatingAdmissionPolicySpec_To_v1alpha1_ValidatingAdmissionPolicySpec(&in.Spec, &out.Spec, s); err != nil { return err } + if err := Convert_admissionregistration_ValidatingAdmissionPolicyStatus_To_v1alpha1_ValidatingAdmissionPolicyStatus(&in.Status, &out.Status, s); err != nil { + return err + } return nil } @@ -544,6 +622,30 @@ func Convert_admissionregistration_ValidatingAdmissionPolicySpec_To_v1alpha1_Val return autoConvert_admissionregistration_ValidatingAdmissionPolicySpec_To_v1alpha1_ValidatingAdmissionPolicySpec(in, out, s) } +func autoConvert_v1alpha1_ValidatingAdmissionPolicyStatus_To_admissionregistration_ValidatingAdmissionPolicyStatus(in *v1alpha1.ValidatingAdmissionPolicyStatus, out *admissionregistration.ValidatingAdmissionPolicyStatus, s conversion.Scope) error { + out.ObservedGeneration = in.ObservedGeneration + out.TypeChecking = (*admissionregistration.TypeChecking)(unsafe.Pointer(in.TypeChecking)) + out.Conditions = *(*[]v1.Condition)(unsafe.Pointer(&in.Conditions)) + return nil +} + +// Convert_v1alpha1_ValidatingAdmissionPolicyStatus_To_admissionregistration_ValidatingAdmissionPolicyStatus is an autogenerated conversion function. +func Convert_v1alpha1_ValidatingAdmissionPolicyStatus_To_admissionregistration_ValidatingAdmissionPolicyStatus(in *v1alpha1.ValidatingAdmissionPolicyStatus, out *admissionregistration.ValidatingAdmissionPolicyStatus, s conversion.Scope) error { + return autoConvert_v1alpha1_ValidatingAdmissionPolicyStatus_To_admissionregistration_ValidatingAdmissionPolicyStatus(in, out, s) +} + +func autoConvert_admissionregistration_ValidatingAdmissionPolicyStatus_To_v1alpha1_ValidatingAdmissionPolicyStatus(in *admissionregistration.ValidatingAdmissionPolicyStatus, out *v1alpha1.ValidatingAdmissionPolicyStatus, s conversion.Scope) error { + out.ObservedGeneration = in.ObservedGeneration + out.TypeChecking = (*v1alpha1.TypeChecking)(unsafe.Pointer(in.TypeChecking)) + out.Conditions = *(*[]v1.Condition)(unsafe.Pointer(&in.Conditions)) + return nil +} + +// Convert_admissionregistration_ValidatingAdmissionPolicyStatus_To_v1alpha1_ValidatingAdmissionPolicyStatus is an autogenerated conversion function. +func Convert_admissionregistration_ValidatingAdmissionPolicyStatus_To_v1alpha1_ValidatingAdmissionPolicyStatus(in *admissionregistration.ValidatingAdmissionPolicyStatus, out *v1alpha1.ValidatingAdmissionPolicyStatus, s conversion.Scope) error { + return autoConvert_admissionregistration_ValidatingAdmissionPolicyStatus_To_v1alpha1_ValidatingAdmissionPolicyStatus(in, out, s) +} + func autoConvert_v1alpha1_Validation_To_admissionregistration_Validation(in *v1alpha1.Validation, out *admissionregistration.Validation, s conversion.Scope) error { out.Expression = in.Expression out.Message = in.Message diff --git a/pkg/apis/admissionregistration/validation/validation.go b/pkg/apis/admissionregistration/validation/validation.go index fe9f60fa988..a3f0b459788 100644 --- a/pkg/apis/admissionregistration/validation/validation.go +++ b/pkg/apis/admissionregistration/validation/validation.go @@ -33,6 +33,7 @@ import ( celconfig "k8s.io/apiserver/pkg/apis/cel" "k8s.io/apiserver/pkg/cel" "k8s.io/apiserver/pkg/util/webhook" + "k8s.io/client-go/util/jsonpath" "k8s.io/kubernetes/pkg/apis/admissionregistration" admissionregistrationv1 "k8s.io/kubernetes/pkg/apis/admissionregistration/v1" @@ -916,7 +917,56 @@ func ValidateValidatingAdmissionPolicyUpdate(newC, oldC *admissionregistration.V return validateValidatingAdmissionPolicy(newC) } +// ValidateValidatingAdmissionPolicyStatusUpdate validates update of status of validating admission policy +func ValidateValidatingAdmissionPolicyStatusUpdate(newC, oldC *admissionregistration.ValidatingAdmissionPolicy) field.ErrorList { + return validateValidatingAdmissionPolicyStatus(&newC.Status, field.NewPath("status")) +} + // ValidateValidatingAdmissionPolicyBindingUpdate validates update of validating admission policy func ValidateValidatingAdmissionPolicyBindingUpdate(newC, oldC *admissionregistration.ValidatingAdmissionPolicyBinding) field.ErrorList { return validateValidatingAdmissionPolicyBinding(newC) } + +func validateValidatingAdmissionPolicyStatus(status *admissionregistration.ValidatingAdmissionPolicyStatus, fldPath *field.Path) field.ErrorList { + var allErrors field.ErrorList + allErrors = append(allErrors, validateTypeChecking(status.TypeChecking, fldPath.Child("typeChecking"))...) + allErrors = append(allErrors, metav1validation.ValidateConditions(status.Conditions, fldPath.Child("conditions"))...) + return allErrors +} + +func validateTypeChecking(typeChecking *admissionregistration.TypeChecking, fldPath *field.Path) field.ErrorList { + if typeChecking == nil { + return nil + } + return validateExpressionWarnings(typeChecking.ExpressionWarnings, fldPath.Child("expressionWarnings")) +} + +func validateExpressionWarnings(expressionWarnings []admissionregistration.ExpressionWarning, fldPath *field.Path) field.ErrorList { + var allErrors field.ErrorList + for i, warning := range expressionWarnings { + allErrors = append(allErrors, validateExpressionWarning(&warning, fldPath.Index(i))...) + } + return allErrors +} + +func validateExpressionWarning(expressionWarning *admissionregistration.ExpressionWarning, fldPath *field.Path) field.ErrorList { + var allErrors field.ErrorList + if expressionWarning.Warning == "" { + allErrors = append(allErrors, field.Required(fldPath.Child("warning"), "")) + } + allErrors = append(allErrors, validateFieldRef(expressionWarning.FieldRef, fldPath.Child("fieldRef"))...) + return allErrors +} + +func validateFieldRef(fieldRef string, fldPath *field.Path) field.ErrorList { + fieldRef = strings.TrimSpace(fieldRef) + if fieldRef == "" { + return field.ErrorList{field.Required(fldPath, "")} + } + jsonPath := jsonpath.New("spec") + if err := jsonPath.Parse(fmt.Sprintf("{%s}", fieldRef)); err != nil { + return field.ErrorList{field.Invalid(fldPath, fieldRef, fmt.Sprintf("invalid JSONPath: %v", err))} + } + // no further checks, for an easier upgrade/rollback + return nil +} diff --git a/pkg/apis/admissionregistration/validation/validation_test.go b/pkg/apis/admissionregistration/validation/validation_test.go index 575d7502064..8db59efa1f1 100644 --- a/pkg/apis/admissionregistration/validation/validation_test.go +++ b/pkg/apis/admissionregistration/validation/validation_test.go @@ -21,6 +21,7 @@ import ( "testing" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/kubernetes/pkg/apis/admissionregistration" ) @@ -3453,3 +3454,83 @@ func TestValidateValidatingAdmissionPolicyBindingUpdate(t *testing.T) { } } + +func TestValidateValidatingAdmissionPolicyStatus(t *testing.T) { + for _, tc := range []struct { + name string + status *admissionregistration.ValidatingAdmissionPolicyStatus + expectedError string + }{ + { + name: "empty", + status: &admissionregistration.ValidatingAdmissionPolicyStatus{}, + }, + { + name: "type checking", + status: &admissionregistration.ValidatingAdmissionPolicyStatus{ + TypeChecking: &admissionregistration.TypeChecking{ + ExpressionWarnings: []admissionregistration.ExpressionWarning{ + { + FieldRef: "spec.validations[0].expression", + Warning: "message", + }, + }, + }, + }, + }, + { + name: "type checking bad json path", + status: &admissionregistration.ValidatingAdmissionPolicyStatus{ + TypeChecking: &admissionregistration.TypeChecking{ + ExpressionWarnings: []admissionregistration.ExpressionWarning{ + { + FieldRef: "spec[foo]", + Warning: "message", + }, + }, + }, + }, + expectedError: "invalid JSONPath: invalid array index foo", + }, + { + name: "type checking missing warning", + status: &admissionregistration.ValidatingAdmissionPolicyStatus{ + TypeChecking: &admissionregistration.TypeChecking{ + ExpressionWarnings: []admissionregistration.ExpressionWarning{ + { + FieldRef: "spec.validations[0].expression", + }, + }, + }, + }, + expectedError: "Required value", + }, + { + name: "type checking missing fieldRef", + status: &admissionregistration.ValidatingAdmissionPolicyStatus{ + TypeChecking: &admissionregistration.TypeChecking{ + ExpressionWarnings: []admissionregistration.ExpressionWarning{ + { + Warning: "message", + }, + }, + }, + }, + expectedError: "Required value", + }, + } { + t.Run(tc.name, func(t *testing.T) { + errs := validateValidatingAdmissionPolicyStatus(tc.status, field.NewPath("status")) + err := errs.ToAggregate() + if err != nil { + if e, a := tc.expectedError, err.Error(); !strings.Contains(a, e) || e == "" { + t.Errorf("expected to contain %s, got %s", e, a) + } + } else { + if tc.expectedError != "" { + t.Errorf("unexpected no error, expected to contain %s", tc.expectedError) + } + } + }) + } +} diff --git a/pkg/apis/admissionregistration/zz_generated.deepcopy.go b/pkg/apis/admissionregistration/zz_generated.deepcopy.go index cad50080816..03a65c6c1cf 100644 --- a/pkg/apis/admissionregistration/zz_generated.deepcopy.go +++ b/pkg/apis/admissionregistration/zz_generated.deepcopy.go @@ -42,6 +42,22 @@ func (in *AuditAnnotation) DeepCopy() *AuditAnnotation { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExpressionWarning) DeepCopyInto(out *ExpressionWarning) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExpressionWarning. +func (in *ExpressionWarning) DeepCopy() *ExpressionWarning { + if in == nil { + return nil + } + out := new(ExpressionWarning) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MatchResources) DeepCopyInto(out *MatchResources) { *out = *in @@ -350,12 +366,34 @@ func (in *ServiceReference) DeepCopy() *ServiceReference { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TypeChecking) DeepCopyInto(out *TypeChecking) { + *out = *in + if in.ExpressionWarnings != nil { + in, out := &in.ExpressionWarnings, &out.ExpressionWarnings + *out = make([]ExpressionWarning, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TypeChecking. +func (in *TypeChecking) DeepCopy() *TypeChecking { + if in == nil { + return nil + } + out := new(TypeChecking) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ValidatingAdmissionPolicy) DeepCopyInto(out *ValidatingAdmissionPolicy) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) return } @@ -544,6 +582,34 @@ func (in *ValidatingAdmissionPolicySpec) DeepCopy() *ValidatingAdmissionPolicySp return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ValidatingAdmissionPolicyStatus) DeepCopyInto(out *ValidatingAdmissionPolicyStatus) { + *out = *in + if in.TypeChecking != nil { + in, out := &in.TypeChecking, &out.TypeChecking + *out = new(TypeChecking) + (*in).DeepCopyInto(*out) + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ValidatingAdmissionPolicyStatus. +func (in *ValidatingAdmissionPolicyStatus) DeepCopy() *ValidatingAdmissionPolicyStatus { + if in == nil { + return nil + } + out := new(ValidatingAdmissionPolicyStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ValidatingWebhook) DeepCopyInto(out *ValidatingWebhook) { *out = *in diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index 7b99e260ea1..8f5db0679c4 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -46,16 +46,19 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "k8s.io/api/admissionregistration/v1.ValidatingWebhookConfigurationList": schema_k8sio_api_admissionregistration_v1_ValidatingWebhookConfigurationList(ref), "k8s.io/api/admissionregistration/v1.WebhookClientConfig": schema_k8sio_api_admissionregistration_v1_WebhookClientConfig(ref), "k8s.io/api/admissionregistration/v1alpha1.AuditAnnotation": schema_k8sio_api_admissionregistration_v1alpha1_AuditAnnotation(ref), + "k8s.io/api/admissionregistration/v1alpha1.ExpressionWarning": schema_k8sio_api_admissionregistration_v1alpha1_ExpressionWarning(ref), "k8s.io/api/admissionregistration/v1alpha1.MatchResources": schema_k8sio_api_admissionregistration_v1alpha1_MatchResources(ref), "k8s.io/api/admissionregistration/v1alpha1.NamedRuleWithOperations": schema_k8sio_api_admissionregistration_v1alpha1_NamedRuleWithOperations(ref), "k8s.io/api/admissionregistration/v1alpha1.ParamKind": schema_k8sio_api_admissionregistration_v1alpha1_ParamKind(ref), "k8s.io/api/admissionregistration/v1alpha1.ParamRef": schema_k8sio_api_admissionregistration_v1alpha1_ParamRef(ref), + "k8s.io/api/admissionregistration/v1alpha1.TypeChecking": schema_k8sio_api_admissionregistration_v1alpha1_TypeChecking(ref), "k8s.io/api/admissionregistration/v1alpha1.ValidatingAdmissionPolicy": schema_k8sio_api_admissionregistration_v1alpha1_ValidatingAdmissionPolicy(ref), "k8s.io/api/admissionregistration/v1alpha1.ValidatingAdmissionPolicyBinding": schema_k8sio_api_admissionregistration_v1alpha1_ValidatingAdmissionPolicyBinding(ref), "k8s.io/api/admissionregistration/v1alpha1.ValidatingAdmissionPolicyBindingList": schema_k8sio_api_admissionregistration_v1alpha1_ValidatingAdmissionPolicyBindingList(ref), "k8s.io/api/admissionregistration/v1alpha1.ValidatingAdmissionPolicyBindingSpec": schema_k8sio_api_admissionregistration_v1alpha1_ValidatingAdmissionPolicyBindingSpec(ref), "k8s.io/api/admissionregistration/v1alpha1.ValidatingAdmissionPolicyList": schema_k8sio_api_admissionregistration_v1alpha1_ValidatingAdmissionPolicyList(ref), "k8s.io/api/admissionregistration/v1alpha1.ValidatingAdmissionPolicySpec": schema_k8sio_api_admissionregistration_v1alpha1_ValidatingAdmissionPolicySpec(ref), + "k8s.io/api/admissionregistration/v1alpha1.ValidatingAdmissionPolicyStatus": schema_k8sio_api_admissionregistration_v1alpha1_ValidatingAdmissionPolicyStatus(ref), "k8s.io/api/admissionregistration/v1alpha1.Validation": schema_k8sio_api_admissionregistration_v1alpha1_Validation(ref), "k8s.io/api/admissionregistration/v1beta1.MutatingWebhook": schema_k8sio_api_admissionregistration_v1beta1_MutatingWebhook(ref), "k8s.io/api/admissionregistration/v1beta1.MutatingWebhookConfiguration": schema_k8sio_api_admissionregistration_v1beta1_MutatingWebhookConfiguration(ref), @@ -1889,6 +1892,36 @@ func schema_k8sio_api_admissionregistration_v1alpha1_AuditAnnotation(ref common. } } +func schema_k8sio_api_admissionregistration_v1alpha1_ExpressionWarning(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ExpressionWarning is a warning information that targets a specific expression.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "fieldRef": { + SchemaProps: spec.SchemaProps{ + Description: "The path to the field that refers the expression. For example, the reference to the expression of the first item of validations is \"spec.validations[0].expression\"", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "warning": { + SchemaProps: spec.SchemaProps{ + Description: "The content of type checking information in a human-readable form. Each line of the warning contains the type that the expression is checked against, followed by the type check error from the compiler.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"fieldRef", "warning"}, + }, + }, + } +} + func schema_k8sio_api_admissionregistration_v1alpha1_MatchResources(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -2156,6 +2189,40 @@ func schema_k8sio_api_admissionregistration_v1alpha1_ParamRef(ref common.Referen } } +func schema_k8sio_api_admissionregistration_v1alpha1_TypeChecking(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TypeChecking contains results of type checking the expressions in the ValidatingAdmissionPolicy", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "expressionWarnings": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "The type checking warnings for each expression.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/api/admissionregistration/v1alpha1.ExpressionWarning"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/api/admissionregistration/v1alpha1.ExpressionWarning"}, + } +} + func schema_k8sio_api_admissionregistration_v1alpha1_ValidatingAdmissionPolicy(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -2191,11 +2258,18 @@ func schema_k8sio_api_admissionregistration_v1alpha1_ValidatingAdmissionPolicy(r Ref: ref("k8s.io/api/admissionregistration/v1alpha1.ValidatingAdmissionPolicySpec"), }, }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "The status of the ValidatingAdmissionPolicy, including warnings that are useful to determine if the policy behaves in the expected way. Populated by the system. Read-only.", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/api/admissionregistration/v1alpha1.ValidatingAdmissionPolicyStatus"), + }, + }, }, }, }, Dependencies: []string{ - "k8s.io/api/admissionregistration/v1alpha1.ValidatingAdmissionPolicySpec", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + "k8s.io/api/admissionregistration/v1alpha1.ValidatingAdmissionPolicySpec", "k8s.io/api/admissionregistration/v1alpha1.ValidatingAdmissionPolicyStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, } } @@ -2469,6 +2543,56 @@ func schema_k8sio_api_admissionregistration_v1alpha1_ValidatingAdmissionPolicySp } } +func schema_k8sio_api_admissionregistration_v1alpha1_ValidatingAdmissionPolicyStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ValidatingAdmissionPolicyStatus represents the status of a ValidatingAdmissionPolicy.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "observedGeneration": { + SchemaProps: spec.SchemaProps{ + Description: "The generation observed by the controller.", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "typeChecking": { + SchemaProps: spec.SchemaProps{ + Description: "The results of type checking for each expression. Presence of this field indicates the completion of the type checking.", + Ref: ref("k8s.io/api/admissionregistration/v1alpha1.TypeChecking"), + }, + }, + "conditions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "type", + }, + "x-kubernetes-list-type": "map", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "The conditions represent the latest available observations of a policy's current state.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/api/admissionregistration/v1alpha1.TypeChecking", "k8s.io/apimachinery/pkg/apis/meta/v1.Condition"}, + } +} + func schema_k8sio_api_admissionregistration_v1alpha1_Validation(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/pkg/kubeapiserver/admission/config.go b/pkg/kubeapiserver/admission/config.go index 6717f839a6f..b9fca885133 100644 --- a/pkg/kubeapiserver/admission/config.go +++ b/pkg/kubeapiserver/admission/config.go @@ -28,6 +28,7 @@ import ( utilwait "k8s.io/apimachinery/pkg/util/wait" "k8s.io/apiserver/pkg/admission" webhookinit "k8s.io/apiserver/pkg/admission/plugin/webhook/initializer" + "k8s.io/apiserver/pkg/cel/openapi/resolver" genericapiserver "k8s.io/apiserver/pkg/server" egressselector "k8s.io/apiserver/pkg/server/egressselector" "k8s.io/apiserver/pkg/util/webhook" @@ -47,7 +48,7 @@ type Config struct { } // New sets up the plugins and admission start hooks needed for admission -func (c *Config) New(proxyTransport *http.Transport, egressSelector *egressselector.EgressSelector, serviceResolver webhook.ServiceResolver, tp trace.TracerProvider) ([]admission.PluginInitializer, genericapiserver.PostStartHookFunc, error) { +func (c *Config) New(proxyTransport *http.Transport, egressSelector *egressselector.EgressSelector, serviceResolver webhook.ServiceResolver, tp trace.TracerProvider, schemaResolver resolver.SchemaResolver) ([]admission.PluginInitializer, genericapiserver.PostStartHookFunc, error) { webhookAuthResolverWrapper := webhook.NewDefaultAuthenticationInfoResolverWrapper(proxyTransport, egressSelector, c.LoopbackClientConfig, tp) webhookPluginInitializer := webhookinit.NewPluginInitializer(webhookAuthResolverWrapper, serviceResolver) @@ -63,13 +64,13 @@ func (c *Config) New(proxyTransport *http.Transport, egressSelector *egressselec if err != nil { return nil, nil, err } - discoveryClient := cacheddiscovery.NewMemCacheClient(clientset.Discovery()) discoveryRESTMapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient) kubePluginInitializer := NewPluginInitializer( cloudConfig, discoveryRESTMapper, quotainstall.NewQuotaConfigurationForAdmission(), + schemaResolver, ) admissionPostStartHook := func(context genericapiserver.PostStartHookContext) error { diff --git a/pkg/kubeapiserver/admission/initializer.go b/pkg/kubeapiserver/admission/initializer.go index 0ba97b5427b..40feff35c35 100644 --- a/pkg/kubeapiserver/admission/initializer.go +++ b/pkg/kubeapiserver/admission/initializer.go @@ -20,6 +20,7 @@ import ( "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/admission/initializer" + "k8s.io/apiserver/pkg/cel/openapi/resolver" quota "k8s.io/apiserver/pkg/quota/v1" ) @@ -35,6 +36,7 @@ type PluginInitializer struct { cloudConfig []byte restMapper meta.RESTMapper quotaConfiguration quota.Configuration + schemaResolver resolver.SchemaResolver } var _ admission.PluginInitializer = &PluginInitializer{} @@ -46,11 +48,13 @@ func NewPluginInitializer( cloudConfig []byte, restMapper meta.RESTMapper, quotaConfiguration quota.Configuration, + schemaResolver resolver.SchemaResolver, ) *PluginInitializer { return &PluginInitializer{ cloudConfig: cloudConfig, restMapper: restMapper, quotaConfiguration: quotaConfiguration, + schemaResolver: schemaResolver, } } @@ -68,4 +72,8 @@ func (i *PluginInitializer) Initialize(plugin admission.Interface) { if wants, ok := plugin.(initializer.WantsQuotaConfiguration); ok { wants.SetQuotaConfiguration(i.quotaConfiguration) } + + if wants, ok := plugin.(initializer.WantsSchemaResolver); ok { + wants.SetSchemaResolver(i.schemaResolver) + } } diff --git a/pkg/kubeapiserver/admission/initializer_test.go b/pkg/kubeapiserver/admission/initializer_test.go index a9fdd5fcece..f4fa85e812c 100644 --- a/pkg/kubeapiserver/admission/initializer_test.go +++ b/pkg/kubeapiserver/admission/initializer_test.go @@ -49,7 +49,7 @@ func (p *WantsCloudConfigAdmissionPlugin) SetCloudConfig(cloudConfig []byte) { func TestCloudConfigAdmissionPlugin(t *testing.T) { cloudConfig := []byte("cloud-configuration") - initializer := NewPluginInitializer(cloudConfig, nil, nil) + initializer := NewPluginInitializer(cloudConfig, nil, nil, nil) wantsCloudConfigAdmission := &WantsCloudConfigAdmissionPlugin{} initializer.Initialize(wantsCloudConfigAdmission) @@ -94,7 +94,7 @@ func (p *WantsRESTMapperAdmissionPlugin) SetRESTMapper(mapper meta.RESTMapper) { func TestRESTMapperAdmissionPlugin(t *testing.T) { mapper := doNothingRESTMapper{} - initializer := NewPluginInitializer(nil, mapper, nil) + initializer := NewPluginInitializer(nil, mapper, nil, nil) wantsRESTMapperAdmission := &WantsRESTMapperAdmissionPlugin{} initializer.Initialize(wantsRESTMapperAdmission) @@ -121,7 +121,7 @@ func (p *WantsQuotaConfigurationAdmissionPlugin) SetQuotaConfiguration(config qu func TestQuotaConfigurationAdmissionPlugin(t *testing.T) { config := doNothingQuotaConfiguration{} - initializer := NewPluginInitializer(nil, nil, config) + initializer := NewPluginInitializer(nil, nil, config, nil) wantsQuotaConfigurationAdmission := &WantsQuotaConfigurationAdmissionPlugin{} initializer.Initialize(wantsQuotaConfigurationAdmission) diff --git a/pkg/registry/admissionregistration/rest/storage_apiserver.go b/pkg/registry/admissionregistration/rest/storage_apiserver.go index 49dd31f028d..6752bc26eb4 100644 --- a/pkg/registry/admissionregistration/rest/storage_apiserver.go +++ b/pkg/registry/admissionregistration/rest/storage_apiserver.go @@ -95,12 +95,13 @@ func (p RESTStorageProvider) v1alpha1Storage(apiResourceConfigSource serverstora // validatingadmissionpolicies if resource := "validatingadmissionpolicies"; apiResourceConfigSource.ResourceEnabled(admissionregistrationv1alpha1.SchemeGroupVersion.WithResource(resource)) { - policyStorage, err := validatingadmissionpolicystorage.NewREST(restOptionsGetter, p.Authorizer, r) + policyStorage, policyStatusStorage, err := validatingadmissionpolicystorage.NewREST(restOptionsGetter, p.Authorizer, r) if err != nil { return storage, err } policyGetter = policyStorage storage[resource] = policyStorage + storage[resource+"/status"] = policyStatusStorage } // validatingadmissionpolicybindings diff --git a/pkg/registry/admissionregistration/validatingadmissionpolicy/storage/storage.go b/pkg/registry/admissionregistration/validatingadmissionpolicy/storage/storage.go index dfdf9339a17..c3382b65cfb 100644 --- a/pkg/registry/admissionregistration/validatingadmissionpolicy/storage/storage.go +++ b/pkg/registry/admissionregistration/validatingadmissionpolicy/storage/storage.go @@ -17,6 +17,9 @@ limitations under the License. package storage import ( + "context" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/registry/generic" @@ -28,6 +31,7 @@ import ( printerstorage "k8s.io/kubernetes/pkg/printers/storage" "k8s.io/kubernetes/pkg/registry/admissionregistration/resolver" "k8s.io/kubernetes/pkg/registry/admissionregistration/validatingadmissionpolicy" + "sigs.k8s.io/structured-merge-diff/v4/fieldpath" ) // REST implements a RESTStorage for validatingAdmissionPolicy against etcd @@ -35,10 +39,16 @@ type REST struct { *genericregistry.Store } +// StatusREST implements a RESTStorage for ValidatingAdmissionPolicyStatus +type StatusREST struct { + // DO NOT embed Store, manually select function to export. + store *genericregistry.Store +} + var groupResource = admissionregistration.Resource("validatingadmissionpolicies") -// NewREST returns a RESTStorage object that will work against validatingAdmissionPolicy. -func NewREST(optsGetter generic.RESTOptionsGetter, authorizer authorizer.Authorizer, resourceResolver resolver.ResourceResolver) (*REST, error) { +// NewREST returns two RESTStorage objects that will work against validatingAdmissionPolicy and its status. +func NewREST(optsGetter generic.RESTOptionsGetter, authorizer authorizer.Authorizer, resourceResolver resolver.ResourceResolver) (*REST, *StatusREST, error) { r := &REST{} strategy := validatingadmissionpolicy.NewStrategy(authorizer, resourceResolver) store := &genericregistry.Store{ @@ -50,18 +60,24 @@ func NewREST(optsGetter generic.RESTOptionsGetter, authorizer authorizer.Authori DefaultQualifiedResource: groupResource, SingularQualifiedResource: admissionregistration.Resource("validatingadmissionpolicy"), - CreateStrategy: strategy, - UpdateStrategy: strategy, - DeleteStrategy: strategy, + CreateStrategy: strategy, + UpdateStrategy: strategy, + DeleteStrategy: strategy, + ResetFieldsStrategy: strategy, TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)}, } options := &generic.StoreOptions{RESTOptions: optsGetter} if err := store.CompleteWithOptions(options); err != nil { - return nil, err + return nil, nil, err } r.Store = store - return r, nil + statusStrategy := validatingadmissionpolicy.NewStatusStrategy(strategy) + statusStore := *store + statusStore.UpdateStrategy = statusStrategy + statusStore.ResetFieldsStrategy = statusStrategy + sr := &StatusREST{store: &statusStore} + return r, sr, nil } // Implement CategoriesProvider @@ -71,3 +87,34 @@ var _ rest.CategoriesProvider = &REST{} func (r *REST) Categories() []string { return []string{"api-extensions"} } + +// New generates a new ValidatingAdmissionPolicy object +func (r *StatusREST) New() runtime.Object { + return &admissionregistration.ValidatingAdmissionPolicy{} +} + +// Destroy disposes the store object. For the StatusREST, this is a no-op. +func (r *StatusREST) Destroy() { + // Given that underlying store is shared with REST, + // we don't destroy it here explicitly. +} + +// Get retrieves the object from the storage. It is required to support Patch. +func (r *StatusREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { + return r.store.Get(ctx, name, options) +} + +// GetResetFields returns the fields that got reset by the REST endpoint +func (r *StatusREST) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { + return r.store.GetResetFields() +} + +// ConvertToTable delegates to the store, implements TableConverter +func (r *StatusREST) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) { + return r.store.ConvertToTable(ctx, object, tableOptions) +} + +// Update alters the status subset of an object. Delegates to the store +func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) { + return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, forceAllowCreate, options) +} diff --git a/pkg/registry/admissionregistration/validatingadmissionpolicy/storage/storage_test.go b/pkg/registry/admissionregistration/validatingadmissionpolicy/storage/storage_test.go index 02c2d134848..29c35559873 100644 --- a/pkg/registry/admissionregistration/validatingadmissionpolicy/storage/storage_test.go +++ b/pkg/registry/admissionregistration/validatingadmissionpolicy/storage/storage_test.go @@ -211,7 +211,7 @@ func newStorage(t *testing.T, authorizer authorizer.Authorizer, resourceResolver Decorator: generic.UndecoratedStorage, DeleteCollectionWorkers: 1, ResourcePrefix: "validatingadmissionpolicies"} - storage, err := NewREST(restOptions, authorizer, resourceResolver) + storage, _, err := NewREST(restOptions, authorizer, resourceResolver) if err != nil { t.Fatalf("unexpected error from REST storage: %v", err) } diff --git a/pkg/registry/admissionregistration/validatingadmissionpolicy/strategy.go b/pkg/registry/admissionregistration/validatingadmissionpolicy/strategy.go index 70bc547048f..2f980c4c82c 100644 --- a/pkg/registry/admissionregistration/validatingadmissionpolicy/strategy.go +++ b/pkg/registry/admissionregistration/validatingadmissionpolicy/strategy.go @@ -19,7 +19,10 @@ package validatingadmissionpolicy import ( "context" + "sigs.k8s.io/structured-merge-diff/v4/fieldpath" + apiequality "k8s.io/apimachinery/pkg/api/equality" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/authorization/authorizer" @@ -56,6 +59,7 @@ func (v *validatingAdmissionPolicyStrategy) NamespaceScoped() bool { // PrepareForCreate clears the status of an validatingAdmissionPolicy before creation. func (v *validatingAdmissionPolicyStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) { ic := obj.(*admissionregistration.ValidatingAdmissionPolicy) + ic.Status = admissionregistration.ValidatingAdmissionPolicyStatus{} ic.Generation = 1 } @@ -64,6 +68,9 @@ func (v *validatingAdmissionPolicyStrategy) PrepareForUpdate(ctx context.Context newIC := obj.(*admissionregistration.ValidatingAdmissionPolicy) oldIC := old.(*admissionregistration.ValidatingAdmissionPolicy) + // Prevent any update on the Status object + newIC.Status = oldIC.Status + // Any changes to the spec increment the generation number, any changes to the // status should reflect the generation number of the corresponding object. // See metav1.ObjectMeta description for more information on Generation. @@ -120,3 +127,53 @@ func (v *validatingAdmissionPolicyStrategy) WarningsOnUpdate(ctx context.Context func (v *validatingAdmissionPolicyStrategy) AllowUnconditionalUpdate() bool { return false } + +// GetResetFields returns the set of fields that get reset by the strategy +// and should not be modified by the user. +func (v *validatingAdmissionPolicyStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { + fields := map[fieldpath.APIVersion]*fieldpath.Set{ + "admissionregistration.k8s.io/v1alpha1": fieldpath.NewSet( + fieldpath.MakePathOrDie("status"), + ), + } + + return fields +} + +type validatingAdmissionPolicyStatusStrategy struct { + *validatingAdmissionPolicyStrategy +} + +// ValidateUpdate is the default update validation of an update to the status object. +func (s *validatingAdmissionPolicyStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { + return validation.ValidateValidatingAdmissionPolicyStatusUpdate(obj.(*admissionregistration.ValidatingAdmissionPolicy), old.(*admissionregistration.ValidatingAdmissionPolicy)) +} + +// PrepareForUpdate differs from the main strategy where setting the spec is not +// allowed, but setting status is OK. +func (s *validatingAdmissionPolicyStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { + newIC := obj.(*admissionregistration.ValidatingAdmissionPolicy) + oldIC := old.(*admissionregistration.ValidatingAdmissionPolicy) + + // Prevent any update on the Spec object from Status Strategy + newIC.Spec = oldIC.Spec + + metav1.ResetObjectMetaForStatus(&newIC.ObjectMeta, &oldIC.ObjectMeta) + // No change in the generation. +} + +// GetResetFields returns the set of fields that get reset by the strategy +// and should not be modified by the user. +func (s *validatingAdmissionPolicyStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { + return map[fieldpath.APIVersion]*fieldpath.Set{ + "admissionregistration.k8s.io/v1alpha1": fieldpath.NewSet( + fieldpath.MakePathOrDie("spec"), + fieldpath.MakePathOrDie("metadata"), + ), + } +} + +// NewStatusStrategy creates a strategy for operating the status object. +func NewStatusStrategy(policyStrategy *validatingAdmissionPolicyStrategy) *validatingAdmissionPolicyStatusStrategy { + return &validatingAdmissionPolicyStatusStrategy{validatingAdmissionPolicyStrategy: policyStrategy} +} diff --git a/plugin/pkg/admission/gc/gc_admission_test.go b/plugin/pkg/admission/gc/gc_admission_test.go index d32c7cd2504..889162e29f0 100644 --- a/plugin/pkg/admission/gc/gc_admission_test.go +++ b/plugin/pkg/admission/gc/gc_admission_test.go @@ -139,7 +139,7 @@ func newGCPermissionsEnforcement() (*gcPermissionsEnforcement, error) { return nil, fmt.Errorf("unexpected error while constructing resource list from fake discovery client: %v", err) } restMapper := restmapper.NewDiscoveryRESTMapper(restMapperRes) - pluginInitializer := kubeadmission.NewPluginInitializer(nil, restMapper, nil) + pluginInitializer := kubeadmission.NewPluginInitializer(nil, restMapper, nil, nil) initializersChain := admission.PluginInitializers{} initializersChain = append(initializersChain, genericPluginInitializer) initializersChain = append(initializersChain, pluginInitializer) diff --git a/plugin/pkg/admission/resourcequota/admission_test.go b/plugin/pkg/admission/resourcequota/admission_test.go index a1114331e3c..f98f1cd5c60 100644 --- a/plugin/pkg/admission/resourcequota/admission_test.go +++ b/plugin/pkg/admission/resourcequota/admission_test.go @@ -111,7 +111,7 @@ func createHandlerWithConfig(kubeClient kubernetes.Interface, informerFactory in initializers := admission.PluginInitializers{ genericadmissioninitializer.New(kubeClient, nil, informerFactory, nil, nil, stopCh), - kubeapiserveradmission.NewPluginInitializer(nil, nil, quotaConfiguration), + kubeapiserveradmission.NewPluginInitializer(nil, nil, quotaConfiguration, nil), } initializers.Initialize(handler) diff --git a/staging/src/k8s.io/api/admissionregistration/v1alpha1/generated.pb.go b/staging/src/k8s.io/api/admissionregistration/v1alpha1/generated.pb.go index e51e7950447..5f37a6416f4 100644 --- a/staging/src/k8s.io/api/admissionregistration/v1alpha1/generated.pb.go +++ b/staging/src/k8s.io/api/admissionregistration/v1alpha1/generated.pb.go @@ -73,10 +73,38 @@ func (m *AuditAnnotation) XXX_DiscardUnknown() { var xxx_messageInfo_AuditAnnotation proto.InternalMessageInfo +func (m *ExpressionWarning) Reset() { *m = ExpressionWarning{} } +func (*ExpressionWarning) ProtoMessage() {} +func (*ExpressionWarning) Descriptor() ([]byte, []int) { + return fileDescriptor_c3be8d256e3ae3cf, []int{1} +} +func (m *ExpressionWarning) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ExpressionWarning) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *ExpressionWarning) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExpressionWarning.Merge(m, src) +} +func (m *ExpressionWarning) XXX_Size() int { + return m.Size() +} +func (m *ExpressionWarning) XXX_DiscardUnknown() { + xxx_messageInfo_ExpressionWarning.DiscardUnknown(m) +} + +var xxx_messageInfo_ExpressionWarning proto.InternalMessageInfo + func (m *MatchResources) Reset() { *m = MatchResources{} } func (*MatchResources) ProtoMessage() {} func (*MatchResources) Descriptor() ([]byte, []int) { - return fileDescriptor_c3be8d256e3ae3cf, []int{1} + return fileDescriptor_c3be8d256e3ae3cf, []int{2} } func (m *MatchResources) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -104,7 +132,7 @@ var xxx_messageInfo_MatchResources proto.InternalMessageInfo func (m *NamedRuleWithOperations) Reset() { *m = NamedRuleWithOperations{} } func (*NamedRuleWithOperations) ProtoMessage() {} func (*NamedRuleWithOperations) Descriptor() ([]byte, []int) { - return fileDescriptor_c3be8d256e3ae3cf, []int{2} + return fileDescriptor_c3be8d256e3ae3cf, []int{3} } func (m *NamedRuleWithOperations) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -132,7 +160,7 @@ var xxx_messageInfo_NamedRuleWithOperations proto.InternalMessageInfo func (m *ParamKind) Reset() { *m = ParamKind{} } func (*ParamKind) ProtoMessage() {} func (*ParamKind) Descriptor() ([]byte, []int) { - return fileDescriptor_c3be8d256e3ae3cf, []int{3} + return fileDescriptor_c3be8d256e3ae3cf, []int{4} } func (m *ParamKind) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -160,7 +188,7 @@ var xxx_messageInfo_ParamKind proto.InternalMessageInfo func (m *ParamRef) Reset() { *m = ParamRef{} } func (*ParamRef) ProtoMessage() {} func (*ParamRef) Descriptor() ([]byte, []int) { - return fileDescriptor_c3be8d256e3ae3cf, []int{4} + return fileDescriptor_c3be8d256e3ae3cf, []int{5} } func (m *ParamRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -185,10 +213,38 @@ func (m *ParamRef) XXX_DiscardUnknown() { var xxx_messageInfo_ParamRef proto.InternalMessageInfo +func (m *TypeChecking) Reset() { *m = TypeChecking{} } +func (*TypeChecking) ProtoMessage() {} +func (*TypeChecking) Descriptor() ([]byte, []int) { + return fileDescriptor_c3be8d256e3ae3cf, []int{6} +} +func (m *TypeChecking) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TypeChecking) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *TypeChecking) XXX_Merge(src proto.Message) { + xxx_messageInfo_TypeChecking.Merge(m, src) +} +func (m *TypeChecking) XXX_Size() int { + return m.Size() +} +func (m *TypeChecking) XXX_DiscardUnknown() { + xxx_messageInfo_TypeChecking.DiscardUnknown(m) +} + +var xxx_messageInfo_TypeChecking proto.InternalMessageInfo + func (m *ValidatingAdmissionPolicy) Reset() { *m = ValidatingAdmissionPolicy{} } func (*ValidatingAdmissionPolicy) ProtoMessage() {} func (*ValidatingAdmissionPolicy) Descriptor() ([]byte, []int) { - return fileDescriptor_c3be8d256e3ae3cf, []int{5} + return fileDescriptor_c3be8d256e3ae3cf, []int{7} } func (m *ValidatingAdmissionPolicy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -216,7 +272,7 @@ var xxx_messageInfo_ValidatingAdmissionPolicy proto.InternalMessageInfo func (m *ValidatingAdmissionPolicyBinding) Reset() { *m = ValidatingAdmissionPolicyBinding{} } func (*ValidatingAdmissionPolicyBinding) ProtoMessage() {} func (*ValidatingAdmissionPolicyBinding) Descriptor() ([]byte, []int) { - return fileDescriptor_c3be8d256e3ae3cf, []int{6} + return fileDescriptor_c3be8d256e3ae3cf, []int{8} } func (m *ValidatingAdmissionPolicyBinding) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -244,7 +300,7 @@ var xxx_messageInfo_ValidatingAdmissionPolicyBinding proto.InternalMessageInfo func (m *ValidatingAdmissionPolicyBindingList) Reset() { *m = ValidatingAdmissionPolicyBindingList{} } func (*ValidatingAdmissionPolicyBindingList) ProtoMessage() {} func (*ValidatingAdmissionPolicyBindingList) Descriptor() ([]byte, []int) { - return fileDescriptor_c3be8d256e3ae3cf, []int{7} + return fileDescriptor_c3be8d256e3ae3cf, []int{9} } func (m *ValidatingAdmissionPolicyBindingList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -272,7 +328,7 @@ var xxx_messageInfo_ValidatingAdmissionPolicyBindingList proto.InternalMessageIn func (m *ValidatingAdmissionPolicyBindingSpec) Reset() { *m = ValidatingAdmissionPolicyBindingSpec{} } func (*ValidatingAdmissionPolicyBindingSpec) ProtoMessage() {} func (*ValidatingAdmissionPolicyBindingSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_c3be8d256e3ae3cf, []int{8} + return fileDescriptor_c3be8d256e3ae3cf, []int{10} } func (m *ValidatingAdmissionPolicyBindingSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -300,7 +356,7 @@ var xxx_messageInfo_ValidatingAdmissionPolicyBindingSpec proto.InternalMessageIn func (m *ValidatingAdmissionPolicyList) Reset() { *m = ValidatingAdmissionPolicyList{} } func (*ValidatingAdmissionPolicyList) ProtoMessage() {} func (*ValidatingAdmissionPolicyList) Descriptor() ([]byte, []int) { - return fileDescriptor_c3be8d256e3ae3cf, []int{9} + return fileDescriptor_c3be8d256e3ae3cf, []int{11} } func (m *ValidatingAdmissionPolicyList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -328,7 +384,7 @@ var xxx_messageInfo_ValidatingAdmissionPolicyList proto.InternalMessageInfo func (m *ValidatingAdmissionPolicySpec) Reset() { *m = ValidatingAdmissionPolicySpec{} } func (*ValidatingAdmissionPolicySpec) ProtoMessage() {} func (*ValidatingAdmissionPolicySpec) Descriptor() ([]byte, []int) { - return fileDescriptor_c3be8d256e3ae3cf, []int{10} + return fileDescriptor_c3be8d256e3ae3cf, []int{12} } func (m *ValidatingAdmissionPolicySpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -353,10 +409,38 @@ func (m *ValidatingAdmissionPolicySpec) XXX_DiscardUnknown() { var xxx_messageInfo_ValidatingAdmissionPolicySpec proto.InternalMessageInfo +func (m *ValidatingAdmissionPolicyStatus) Reset() { *m = ValidatingAdmissionPolicyStatus{} } +func (*ValidatingAdmissionPolicyStatus) ProtoMessage() {} +func (*ValidatingAdmissionPolicyStatus) Descriptor() ([]byte, []int) { + return fileDescriptor_c3be8d256e3ae3cf, []int{13} +} +func (m *ValidatingAdmissionPolicyStatus) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ValidatingAdmissionPolicyStatus) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *ValidatingAdmissionPolicyStatus) XXX_Merge(src proto.Message) { + xxx_messageInfo_ValidatingAdmissionPolicyStatus.Merge(m, src) +} +func (m *ValidatingAdmissionPolicyStatus) XXX_Size() int { + return m.Size() +} +func (m *ValidatingAdmissionPolicyStatus) XXX_DiscardUnknown() { + xxx_messageInfo_ValidatingAdmissionPolicyStatus.DiscardUnknown(m) +} + +var xxx_messageInfo_ValidatingAdmissionPolicyStatus proto.InternalMessageInfo + func (m *Validation) Reset() { *m = Validation{} } func (*Validation) ProtoMessage() {} func (*Validation) Descriptor() ([]byte, []int) { - return fileDescriptor_c3be8d256e3ae3cf, []int{11} + return fileDescriptor_c3be8d256e3ae3cf, []int{14} } func (m *Validation) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -383,16 +467,19 @@ var xxx_messageInfo_Validation proto.InternalMessageInfo func init() { proto.RegisterType((*AuditAnnotation)(nil), "k8s.io.api.admissionregistration.v1alpha1.AuditAnnotation") + proto.RegisterType((*ExpressionWarning)(nil), "k8s.io.api.admissionregistration.v1alpha1.ExpressionWarning") proto.RegisterType((*MatchResources)(nil), "k8s.io.api.admissionregistration.v1alpha1.MatchResources") proto.RegisterType((*NamedRuleWithOperations)(nil), "k8s.io.api.admissionregistration.v1alpha1.NamedRuleWithOperations") proto.RegisterType((*ParamKind)(nil), "k8s.io.api.admissionregistration.v1alpha1.ParamKind") proto.RegisterType((*ParamRef)(nil), "k8s.io.api.admissionregistration.v1alpha1.ParamRef") + proto.RegisterType((*TypeChecking)(nil), "k8s.io.api.admissionregistration.v1alpha1.TypeChecking") proto.RegisterType((*ValidatingAdmissionPolicy)(nil), "k8s.io.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicy") proto.RegisterType((*ValidatingAdmissionPolicyBinding)(nil), "k8s.io.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyBinding") proto.RegisterType((*ValidatingAdmissionPolicyBindingList)(nil), "k8s.io.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyBindingList") proto.RegisterType((*ValidatingAdmissionPolicyBindingSpec)(nil), "k8s.io.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyBindingSpec") proto.RegisterType((*ValidatingAdmissionPolicyList)(nil), "k8s.io.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyList") proto.RegisterType((*ValidatingAdmissionPolicySpec)(nil), "k8s.io.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicySpec") + proto.RegisterType((*ValidatingAdmissionPolicyStatus)(nil), "k8s.io.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyStatus") proto.RegisterType((*Validation)(nil), "k8s.io.api.admissionregistration.v1alpha1.Validation") } @@ -401,81 +488,93 @@ func init() { } var fileDescriptor_c3be8d256e3ae3cf = []byte{ - // 1177 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0x4d, 0x6f, 0x1b, 0x45, - 0x18, 0xce, 0xd6, 0x6e, 0x1b, 0x8f, 0x9b, 0xc4, 0x1e, 0x52, 0xd5, 0x8d, 0xa8, 0x1d, 0x59, 0x15, - 0x4a, 0x0e, 0xec, 0x92, 0xb4, 0x50, 0xe0, 0x82, 0xbc, 0xb4, 0x40, 0x95, 0xb8, 0x89, 0x26, 0x28, - 0x91, 0x10, 0x95, 0x98, 0xac, 0x27, 0xf6, 0xd4, 0xde, 0x0f, 0x76, 0x66, 0xa3, 0x44, 0x1c, 0xa8, - 0xc4, 0x89, 0x1b, 0x07, 0x7e, 0x0f, 0xe7, 0x1c, 0x7b, 0x0c, 0x17, 0x8b, 0x98, 0x0b, 0xfc, 0x01, - 0x90, 0x72, 0x01, 0xcd, 0xec, 0xac, 0xf7, 0xc3, 0x36, 0x71, 0x4a, 0xd4, 0x9b, 0xf7, 0xfd, 0x78, - 0x9e, 0x79, 0xde, 0x79, 0xdf, 0x99, 0x31, 0x40, 0xdd, 0x0f, 0x99, 0x4e, 0x5d, 0xa3, 0x1b, 0xec, - 0x13, 0xdf, 0x21, 0x9c, 0x30, 0xe3, 0x90, 0x38, 0x2d, 0xd7, 0x37, 0x94, 0x03, 0x7b, 0xd4, 0xc0, - 0x2d, 0x9b, 0x32, 0x46, 0x5d, 0xc7, 0x27, 0x6d, 0xca, 0xb8, 0x8f, 0x39, 0x75, 0x1d, 0xe3, 0x70, - 0x0d, 0xf7, 0xbc, 0x0e, 0x5e, 0x33, 0xda, 0xc4, 0x21, 0x3e, 0xe6, 0xa4, 0xa5, 0x7b, 0xbe, 0xcb, - 0x5d, 0xb8, 0x1a, 0xa6, 0xea, 0xd8, 0xa3, 0xfa, 0xd8, 0x54, 0x3d, 0x4a, 0x5d, 0x7a, 0xb7, 0x4d, - 0x79, 0x27, 0xd8, 0xd7, 0x2d, 0xd7, 0x36, 0xda, 0x6e, 0xdb, 0x35, 0x24, 0xc2, 0x7e, 0x70, 0x20, - 0xbf, 0xe4, 0x87, 0xfc, 0x15, 0x22, 0x2f, 0x3d, 0x98, 0x62, 0x51, 0xd9, 0xe5, 0x2c, 0x3d, 0x8c, - 0x93, 0x6c, 0x6c, 0x75, 0xa8, 0x43, 0xfc, 0x63, 0xc3, 0xeb, 0xb6, 0x85, 0x81, 0x19, 0x36, 0xe1, - 0x78, 0x5c, 0x96, 0x31, 0x29, 0xcb, 0x0f, 0x1c, 0x4e, 0x6d, 0x32, 0x92, 0xf0, 0xc1, 0x45, 0x09, - 0xcc, 0xea, 0x10, 0x1b, 0x67, 0xf3, 0xea, 0x0c, 0x2c, 0x34, 0x82, 0x16, 0xe5, 0x0d, 0xc7, 0x71, - 0xb9, 0x14, 0x01, 0xef, 0x81, 0x5c, 0x97, 0x1c, 0x57, 0xb4, 0x65, 0x6d, 0xa5, 0x60, 0x16, 0x4f, - 0xfa, 0xb5, 0x99, 0x41, 0xbf, 0x96, 0xdb, 0x20, 0xc7, 0x48, 0xd8, 0x61, 0x03, 0x2c, 0x1c, 0xe2, - 0x5e, 0x40, 0x9e, 0x1c, 0x79, 0x3e, 0x91, 0x25, 0xa8, 0x5c, 0x93, 0xa1, 0x77, 0x54, 0xe8, 0xc2, - 0x6e, 0xda, 0x8d, 0xb2, 0xf1, 0xf5, 0x5f, 0xf3, 0x60, 0xbe, 0x89, 0xb9, 0xd5, 0x41, 0x84, 0xb9, - 0x81, 0x6f, 0x11, 0x06, 0x8f, 0x40, 0xd9, 0xc1, 0x36, 0x61, 0x1e, 0xb6, 0xc8, 0x0e, 0xe9, 0x11, - 0x8b, 0xbb, 0xbe, 0x5c, 0x42, 0x71, 0xfd, 0x81, 0x1e, 0xef, 0xe8, 0x50, 0x9b, 0xee, 0x75, 0xdb, - 0xc2, 0xc0, 0x74, 0x51, 0x42, 0xfd, 0x70, 0x4d, 0xdf, 0xc4, 0xfb, 0xa4, 0x17, 0xa5, 0x9a, 0xb7, - 0x07, 0xfd, 0x5a, 0xf9, 0x59, 0x16, 0x11, 0x8d, 0x92, 0x40, 0x17, 0xcc, 0xbb, 0xfb, 0x2f, 0x88, - 0xc5, 0x87, 0xb4, 0xd7, 0x5e, 0x9f, 0x16, 0x0e, 0xfa, 0xb5, 0xf9, 0xad, 0x14, 0x1c, 0xca, 0xc0, - 0xc3, 0xef, 0xc1, 0x9c, 0xaf, 0x74, 0xa3, 0xa0, 0x47, 0x58, 0x25, 0xb7, 0x9c, 0x5b, 0x29, 0xae, - 0x9b, 0xfa, 0xd4, 0x8d, 0xab, 0x0b, 0x61, 0x2d, 0x91, 0xbc, 0x47, 0x79, 0x67, 0xcb, 0x23, 0xa1, - 0x9f, 0x99, 0xb7, 0xd5, 0x16, 0xcc, 0xa1, 0x24, 0x01, 0x4a, 0xf3, 0xc1, 0x9f, 0x35, 0xb0, 0x48, - 0x8e, 0xac, 0x5e, 0xd0, 0x22, 0xa9, 0xb8, 0x4a, 0xfe, 0xca, 0x16, 0xf2, 0xb6, 0x5a, 0xc8, 0xe2, - 0x93, 0x31, 0x3c, 0x68, 0x2c, 0x3b, 0x7c, 0x0c, 0x8a, 0xb6, 0x68, 0x8a, 0x6d, 0xb7, 0x47, 0xad, - 0xe3, 0xca, 0x4d, 0xd9, 0x54, 0xf5, 0x41, 0xbf, 0x56, 0x6c, 0xc6, 0xe6, 0xf3, 0x7e, 0x6d, 0x21, - 0xf1, 0xf9, 0xe5, 0xb1, 0x47, 0x50, 0x32, 0xad, 0x7e, 0xaa, 0x81, 0x3b, 0x13, 0x56, 0x05, 0x1f, - 0xc5, 0x95, 0x97, 0xad, 0x51, 0xd1, 0x96, 0x73, 0x2b, 0x05, 0xb3, 0x9c, 0xac, 0x98, 0x74, 0xa0, - 0x74, 0x1c, 0xfc, 0x41, 0x03, 0xd0, 0x1f, 0xc1, 0x53, 0x8d, 0xf2, 0x68, 0x9a, 0x7a, 0xe9, 0x63, - 0x8a, 0xb4, 0xa4, 0x8a, 0x04, 0x47, 0x7d, 0x68, 0x0c, 0x5d, 0x1d, 0x83, 0xc2, 0x36, 0xf6, 0xb1, - 0xbd, 0x41, 0x9d, 0x16, 0x5c, 0x07, 0x00, 0x7b, 0x74, 0x97, 0xf8, 0x72, 0x02, 0xc3, 0x61, 0x85, - 0x0a, 0x10, 0x34, 0xb6, 0x9f, 0x2a, 0x0f, 0x4a, 0x44, 0xc1, 0x65, 0x90, 0xef, 0x52, 0xa7, 0xa5, - 0xe6, 0xf5, 0x96, 0x8a, 0xce, 0x0b, 0x3c, 0x24, 0x3d, 0xf5, 0xe7, 0x60, 0x56, 0x52, 0x20, 0x72, - 0x20, 0xa2, 0xc5, 0xb4, 0x28, 0xec, 0x61, 0xb4, 0xa8, 0x08, 0x92, 0x1e, 0x68, 0x80, 0xc2, 0x70, - 0x9e, 0x14, 0x68, 0x59, 0x85, 0x15, 0x86, 0xb3, 0x87, 0xe2, 0x98, 0xfa, 0x9f, 0x1a, 0xb8, 0xbb, - 0x8b, 0x7b, 0xb4, 0x85, 0x39, 0x75, 0xda, 0x8d, 0xa8, 0x56, 0xe1, 0xd6, 0xc1, 0x6f, 0xc0, 0xac, - 0x98, 0xaa, 0x16, 0xe6, 0x58, 0x8d, 0xfe, 0x7b, 0xd3, 0xcd, 0x60, 0x38, 0x70, 0x4d, 0xc2, 0x71, - 0x5c, 0x82, 0xd8, 0x86, 0x86, 0xa8, 0xf0, 0x05, 0xc8, 0x33, 0x8f, 0x58, 0x6a, 0xe3, 0xbe, 0xb8, - 0x44, 0xa3, 0x4f, 0x5c, 0xf5, 0x8e, 0x47, 0xac, 0xb8, 0x38, 0xe2, 0x0b, 0x49, 0x8e, 0xfa, 0xdf, - 0x1a, 0x58, 0x9e, 0x98, 0x65, 0x52, 0xa7, 0x45, 0x9d, 0xf6, 0x1b, 0x90, 0xfc, 0x6d, 0x4a, 0xf2, - 0xd6, 0x55, 0x48, 0x56, 0x8b, 0x9f, 0xa8, 0xfc, 0x2f, 0x0d, 0xdc, 0xbf, 0x28, 0x79, 0x93, 0x32, - 0x0e, 0xbf, 0x1e, 0x51, 0xaf, 0x4f, 0x79, 0xe8, 0x52, 0x16, 0x6a, 0x2f, 0x29, 0xfa, 0xd9, 0xc8, - 0x92, 0x50, 0xee, 0x81, 0xeb, 0x94, 0x13, 0x5b, 0x8c, 0xa9, 0x38, 0xd6, 0x36, 0xae, 0x50, 0xba, - 0x39, 0xa7, 0x78, 0xaf, 0x3f, 0x15, 0x0c, 0x28, 0x24, 0xaa, 0xff, 0x98, 0xbb, 0x58, 0xb8, 0xa8, - 0x93, 0x18, 0x5e, 0x4f, 0x1a, 0x9f, 0xc5, 0x03, 0x36, 0xdc, 0xc6, 0xed, 0xa1, 0x07, 0x25, 0xa2, - 0xe0, 0x73, 0x30, 0xeb, 0xa9, 0xd1, 0x1c, 0x73, 0x43, 0x5d, 0xa4, 0x28, 0x9a, 0x6a, 0xf3, 0x96, - 0xa8, 0x56, 0xf4, 0x85, 0x86, 0x90, 0x30, 0x00, 0xf3, 0x76, 0xea, 0x4a, 0xae, 0xe4, 0x24, 0xc9, - 0x47, 0x97, 0x20, 0x49, 0xdf, 0xe9, 0xe1, 0x65, 0x98, 0xb6, 0xa1, 0x0c, 0x09, 0xdc, 0x03, 0xe5, - 0x43, 0x55, 0x31, 0xd7, 0x69, 0x58, 0xe1, 0xb9, 0x9a, 0x97, 0xc7, 0xf2, 0xaa, 0xb8, 0xc2, 0x77, - 0xb3, 0xce, 0xf3, 0x7e, 0xad, 0x94, 0x35, 0xa2, 0x51, 0x8c, 0xfa, 0x1f, 0x1a, 0xb8, 0x37, 0x71, - 0x2f, 0xde, 0x40, 0xf7, 0xd1, 0x74, 0xf7, 0x3d, 0xbe, 0x92, 0xee, 0x1b, 0xdf, 0x76, 0xbf, 0xe4, - 0xff, 0x43, 0xaa, 0xec, 0x37, 0x0c, 0x0a, 0x5e, 0x74, 0x73, 0x28, 0xad, 0x0f, 0x2f, 0xdb, 0x3c, - 0x22, 0xd7, 0x9c, 0x13, 0x47, 0xfb, 0xf0, 0x13, 0xc5, 0xa8, 0xf0, 0x3b, 0x50, 0x92, 0x5b, 0xfb, - 0xa9, 0xeb, 0x08, 0x00, 0xea, 0xf0, 0xe8, 0x7e, 0xfc, 0x1f, 0x1d, 0xb4, 0x38, 0xe8, 0xd7, 0x4a, - 0xcd, 0x0c, 0x2c, 0x1a, 0x21, 0x82, 0x3d, 0x50, 0x8c, 0x3b, 0x20, 0x7a, 0x50, 0xbd, 0xff, 0x1a, - 0x25, 0x77, 0x1d, 0xf3, 0x2d, 0x55, 0xe3, 0x62, 0x6c, 0x63, 0x28, 0x09, 0x0f, 0x37, 0xc1, 0xdc, - 0x01, 0xa6, 0xbd, 0xc0, 0x27, 0xea, 0xa9, 0x92, 0x97, 0x03, 0xfc, 0x8e, 0x78, 0x46, 0x7c, 0x96, - 0x74, 0x9c, 0xf7, 0x6b, 0xe5, 0x94, 0x41, 0x3e, 0x57, 0xd2, 0xc9, 0xf0, 0xa5, 0x06, 0x4a, 0x38, - 0xfd, 0x04, 0x67, 0x95, 0xeb, 0x52, 0xc1, 0xc7, 0x97, 0x50, 0x90, 0x79, 0xc5, 0x9b, 0x15, 0x25, - 0xa3, 0x94, 0x71, 0x30, 0x34, 0xc2, 0x56, 0xff, 0x47, 0x03, 0x20, 0x56, 0x0b, 0xef, 0x03, 0x90, - 0x78, 0xdc, 0x87, 0xa7, 0x53, 0x5e, 0xc0, 0xa1, 0x84, 0x1d, 0xae, 0x82, 0x9b, 0x36, 0x61, 0x0c, - 0xb7, 0xa3, 0xab, 0x7f, 0x41, 0x31, 0xde, 0x6c, 0x86, 0x66, 0x14, 0xf9, 0xe1, 0x1e, 0xb8, 0xe1, - 0x13, 0xcc, 0x5c, 0x47, 0x9e, 0x29, 0x05, 0xf3, 0x93, 0x41, 0xbf, 0x76, 0x03, 0x49, 0xcb, 0x79, - 0xbf, 0xb6, 0x36, 0xcd, 0x3f, 0x24, 0x7d, 0x87, 0x63, 0x1e, 0xb0, 0x30, 0x09, 0x29, 0x38, 0xf8, - 0x39, 0x28, 0x2b, 0x8e, 0xc4, 0x82, 0xc3, 0xdd, 0xb8, 0xab, 0x56, 0x53, 0x6e, 0x66, 0x03, 0xd0, - 0x68, 0x8e, 0xb9, 0x75, 0x72, 0x56, 0x9d, 0x79, 0x75, 0x56, 0x9d, 0x39, 0x3d, 0xab, 0xce, 0xbc, - 0x1c, 0x54, 0xb5, 0x93, 0x41, 0x55, 0x7b, 0x35, 0xa8, 0x6a, 0xa7, 0x83, 0xaa, 0xf6, 0xdb, 0xa0, - 0xaa, 0xfd, 0xf4, 0x7b, 0x75, 0xe6, 0xab, 0xd5, 0xa9, 0xff, 0x95, 0xfe, 0x1b, 0x00, 0x00, 0xff, - 0xff, 0x47, 0xed, 0x82, 0x0e, 0xda, 0x0e, 0x00, 0x00, + // 1367 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x4b, 0x6f, 0x5b, 0xc5, + 0x17, 0xcf, 0x8d, 0xdd, 0x36, 0x39, 0xce, 0xcb, 0xf3, 0x6f, 0x55, 0x37, 0xfa, 0xd7, 0x8e, 0xae, + 0x2a, 0xd4, 0x48, 0x70, 0x4d, 0xd2, 0x42, 0x01, 0x21, 0xa1, 0xdc, 0xbe, 0xe8, 0x23, 0x4d, 0x34, + 0x45, 0x89, 0x84, 0xa8, 0xc4, 0xe4, 0xde, 0x89, 0x3d, 0xb5, 0xef, 0x83, 0x3b, 0xd7, 0xa1, 0x11, + 0x0b, 0x2a, 0xb1, 0x81, 0x1d, 0x0b, 0x36, 0x7c, 0x19, 0x24, 0x76, 0x5d, 0x76, 0x59, 0x16, 0x58, + 0xd4, 0x6c, 0xf8, 0x04, 0x20, 0x65, 0x03, 0x9a, 0xb9, 0x73, 0x9f, 0x76, 0x88, 0x53, 0x02, 0x3b, + 0xdf, 0xf3, 0xf8, 0xfd, 0xe6, 0x9c, 0x39, 0x73, 0xe6, 0x8c, 0x01, 0x77, 0xde, 0xe1, 0x06, 0xf3, + 0x9a, 0x9d, 0xde, 0x0e, 0x0d, 0x5c, 0x1a, 0x52, 0xde, 0xdc, 0xa3, 0xae, 0xed, 0x05, 0x4d, 0xa5, + 0x20, 0x3e, 0x6b, 0x12, 0xdb, 0x61, 0x9c, 0x33, 0xcf, 0x0d, 0x68, 0x8b, 0xf1, 0x30, 0x20, 0x21, + 0xf3, 0xdc, 0xe6, 0xde, 0x0a, 0xe9, 0xfa, 0x6d, 0xb2, 0xd2, 0x6c, 0x51, 0x97, 0x06, 0x24, 0xa4, + 0xb6, 0xe1, 0x07, 0x5e, 0xe8, 0xa1, 0xe5, 0xc8, 0xd5, 0x20, 0x3e, 0x33, 0x46, 0xba, 0x1a, 0xb1, + 0xeb, 0xe2, 0x1b, 0x2d, 0x16, 0xb6, 0x7b, 0x3b, 0x86, 0xe5, 0x39, 0xcd, 0x96, 0xd7, 0xf2, 0x9a, + 0x12, 0x61, 0xa7, 0xb7, 0x2b, 0xbf, 0xe4, 0x87, 0xfc, 0x15, 0x21, 0x2f, 0x5e, 0x19, 0x63, 0x51, + 0xc5, 0xe5, 0x2c, 0x5e, 0x4d, 0x9d, 0x1c, 0x62, 0xb5, 0x99, 0x4b, 0x83, 0xfd, 0xa6, 0xdf, 0x69, + 0x09, 0x01, 0x6f, 0x3a, 0x34, 0x24, 0xa3, 0xbc, 0x9a, 0x87, 0x79, 0x05, 0x3d, 0x37, 0x64, 0x0e, + 0x1d, 0x72, 0x78, 0xfb, 0x28, 0x07, 0x6e, 0xb5, 0xa9, 0x43, 0x8a, 0x7e, 0x3a, 0x87, 0xf9, 0xb5, + 0x9e, 0xcd, 0xc2, 0x35, 0xd7, 0xf5, 0x42, 0x19, 0x04, 0xba, 0x08, 0xa5, 0x0e, 0xdd, 0xaf, 0x69, + 0x4b, 0xda, 0xe5, 0x69, 0xb3, 0xf2, 0xac, 0xdf, 0x98, 0x18, 0xf4, 0x1b, 0xa5, 0x7b, 0x74, 0x1f, + 0x0b, 0x39, 0x5a, 0x83, 0xf9, 0x3d, 0xd2, 0xed, 0xd1, 0x9b, 0x4f, 0xfc, 0x80, 0xca, 0x14, 0xd4, + 0x26, 0xa5, 0xe9, 0x79, 0x65, 0x3a, 0xbf, 0x95, 0x57, 0xe3, 0xa2, 0xbd, 0xde, 0x85, 0x6a, 0xfa, + 0xb5, 0x4d, 0x02, 0x97, 0xb9, 0x2d, 0xf4, 0x3a, 0x4c, 0xed, 0x32, 0xda, 0xb5, 0x31, 0xdd, 0x55, + 0x80, 0x0b, 0x0a, 0x70, 0xea, 0x96, 0x92, 0xe3, 0xc4, 0x02, 0x2d, 0xc3, 0x99, 0xcf, 0x23, 0xc7, + 0x5a, 0x49, 0x1a, 0xcf, 0x2b, 0xe3, 0x33, 0x0a, 0x0f, 0xc7, 0x7a, 0xfd, 0xa7, 0x32, 0xcc, 0xad, + 0x93, 0xd0, 0x6a, 0x63, 0xca, 0xbd, 0x5e, 0x60, 0x51, 0x8e, 0x9e, 0x40, 0xd5, 0x25, 0x0e, 0xe5, + 0x3e, 0xb1, 0xe8, 0x43, 0xda, 0xa5, 0x56, 0xe8, 0x05, 0x32, 0xe0, 0xca, 0xea, 0x15, 0x23, 0xad, + 0x9f, 0x24, 0x93, 0x86, 0xdf, 0x69, 0x09, 0x01, 0x37, 0xc4, 0x86, 0x19, 0x7b, 0x2b, 0xc6, 0x7d, + 0xb2, 0x43, 0xbb, 0xb1, 0xab, 0x79, 0x6e, 0xd0, 0x6f, 0x54, 0x1f, 0x14, 0x11, 0xf1, 0x30, 0x09, + 0xf2, 0x60, 0xce, 0xdb, 0x79, 0x4c, 0xad, 0x30, 0xa1, 0x9d, 0x7c, 0x75, 0x5a, 0x34, 0xe8, 0x37, + 0xe6, 0x36, 0x72, 0x70, 0xb8, 0x00, 0x8f, 0xbe, 0x84, 0xd9, 0x40, 0xc5, 0x8d, 0x7b, 0x5d, 0xca, + 0x6b, 0xa5, 0xa5, 0xd2, 0xe5, 0xca, 0xaa, 0x69, 0x8c, 0x7d, 0x4c, 0x0c, 0x11, 0x98, 0x2d, 0x9c, + 0xb7, 0x59, 0xd8, 0xde, 0xf0, 0x69, 0xa4, 0xe7, 0xe6, 0x39, 0x95, 0xf2, 0x59, 0x9c, 0x25, 0xc0, + 0x79, 0x3e, 0xf4, 0x9d, 0x06, 0x67, 0xe9, 0x13, 0xab, 0xdb, 0xb3, 0x69, 0xce, 0xae, 0x56, 0x3e, + 0xb1, 0x85, 0xfc, 0x5f, 0x2d, 0xe4, 0xec, 0xcd, 0x11, 0x3c, 0x78, 0x24, 0x3b, 0xba, 0x01, 0x15, + 0x47, 0x14, 0xc5, 0xa6, 0xd7, 0x65, 0xd6, 0x7e, 0xed, 0x8c, 0x2c, 0x22, 0x7d, 0xd0, 0x6f, 0x54, + 0xd6, 0x53, 0xf1, 0x41, 0xbf, 0x31, 0x9f, 0xf9, 0xfc, 0x68, 0xdf, 0xa7, 0x38, 0xeb, 0xa6, 0xbf, + 0xd0, 0xe0, 0xfc, 0x21, 0xab, 0x42, 0xd7, 0xd2, 0xcc, 0xcb, 0xd2, 0xa8, 0x69, 0x4b, 0xa5, 0xcb, + 0xd3, 0x66, 0x35, 0x9b, 0x31, 0xa9, 0xc0, 0x79, 0x3b, 0xf4, 0x95, 0x06, 0x28, 0x18, 0xc2, 0x53, + 0x85, 0x72, 0x6d, 0x9c, 0x7c, 0x19, 0x23, 0x92, 0xb4, 0xa8, 0x92, 0x84, 0x86, 0x75, 0x78, 0x04, + 0x9d, 0x4e, 0x60, 0x7a, 0x93, 0x04, 0xc4, 0xb9, 0xc7, 0x5c, 0x1b, 0xad, 0x02, 0x10, 0x9f, 0x6d, + 0xd1, 0x40, 0x9e, 0xf7, 0xa8, 0x35, 0x20, 0x05, 0x08, 0x6b, 0x9b, 0x77, 0x94, 0x06, 0x67, 0xac, + 0xd0, 0x12, 0x94, 0x3b, 0xcc, 0xb5, 0xd5, 0x61, 0x9e, 0x51, 0xd6, 0x65, 0x81, 0x87, 0xa5, 0x46, + 0x7f, 0x04, 0x53, 0x92, 0x42, 0x1c, 0xe8, 0x25, 0x28, 0x8b, 0xd3, 0xa2, 0xb0, 0x13, 0x6b, 0x91, + 0x11, 0x2c, 0x35, 0xa8, 0x09, 0xd3, 0xc9, 0x79, 0x52, 0xa0, 0x55, 0x65, 0x36, 0x9d, 0x9c, 0x3d, + 0x9c, 0xda, 0xe8, 0xdf, 0x6b, 0x30, 0x23, 0xb6, 0xec, 0x7a, 0x9b, 0x5a, 0x1d, 0xd1, 0x62, 0xbe, + 0xd6, 0x00, 0xd1, 0x62, 0xe3, 0x89, 0xf6, 0xa5, 0xb2, 0xfa, 0xfe, 0x31, 0x0a, 0x71, 0xa8, 0x7b, + 0xa5, 0xd9, 0x1d, 0x52, 0x71, 0x3c, 0x82, 0x53, 0xff, 0x79, 0x12, 0x2e, 0x6c, 0x91, 0x2e, 0xb3, + 0x49, 0xc8, 0xdc, 0xd6, 0x5a, 0x4c, 0x17, 0x95, 0x15, 0xfa, 0x14, 0xa6, 0xc4, 0x89, 0xb7, 0x49, + 0x48, 0x54, 0x5b, 0x7a, 0x73, 0xbc, 0xfe, 0x10, 0x35, 0x83, 0x75, 0x1a, 0x92, 0x74, 0x7b, 0x52, + 0x19, 0x4e, 0x50, 0xd1, 0x63, 0x28, 0x73, 0x9f, 0x5a, 0xaa, 0xa8, 0x3e, 0x3c, 0x46, 0xec, 0x87, + 0xae, 0xfa, 0xa1, 0x4f, 0xad, 0x74, 0xe3, 0xc4, 0x17, 0x96, 0x1c, 0x28, 0x80, 0xd3, 0x3c, 0x24, + 0x61, 0x8f, 0xcb, 0x56, 0x5d, 0x59, 0xbd, 0x7b, 0x22, 0x6c, 0x12, 0xd1, 0x9c, 0x53, 0x7c, 0xa7, + 0xa3, 0x6f, 0xac, 0x98, 0xf4, 0x3f, 0x34, 0x58, 0x3a, 0xd4, 0xd7, 0x64, 0xae, 0x2d, 0xea, 0xe1, + 0xdf, 0x4f, 0xf3, 0x67, 0xb9, 0x34, 0x6f, 0x9c, 0x44, 0xe0, 0x6a, 0xf1, 0x87, 0x65, 0x5b, 0xff, + 0x5d, 0x83, 0x4b, 0x47, 0x39, 0xdf, 0x67, 0x3c, 0x44, 0x9f, 0x0c, 0x45, 0x6f, 0x8c, 0x79, 0x09, + 0x31, 0x1e, 0xc5, 0x9e, 0x5c, 0xd0, 0xb1, 0x24, 0x13, 0xb9, 0x0f, 0xa7, 0x58, 0x48, 0x1d, 0xd1, + 0xb6, 0xc4, 0xe9, 0xba, 0x77, 0x82, 0xa1, 0x9b, 0xb3, 0x8a, 0xf7, 0xd4, 0x1d, 0xc1, 0x80, 0x23, + 0x22, 0xfd, 0x9b, 0xd2, 0xd1, 0x81, 0x8b, 0x3c, 0x89, 0x66, 0xe6, 0x4b, 0xe1, 0x83, 0xb4, 0xe1, + 0x24, 0xdb, 0xb8, 0x99, 0x68, 0x70, 0xc6, 0x0a, 0x3d, 0x82, 0x29, 0x5f, 0xb5, 0xaa, 0x11, 0x37, + 0xf6, 0x51, 0x11, 0xc5, 0x5d, 0xce, 0x9c, 0x11, 0xd9, 0x8a, 0xbf, 0x70, 0x02, 0x89, 0x7a, 0x30, + 0xe7, 0xe4, 0x46, 0x14, 0x75, 0x54, 0xde, 0x3d, 0x06, 0x49, 0x7e, 0xc6, 0x89, 0x86, 0x83, 0xbc, + 0x0c, 0x17, 0x48, 0xd0, 0x36, 0x54, 0xf7, 0x54, 0xc6, 0x3c, 0x77, 0xcd, 0x8a, 0xee, 0x99, 0xb2, + 0xbc, 0xa6, 0x96, 0xc5, 0x48, 0xb3, 0x55, 0x54, 0x1e, 0xf4, 0x1b, 0x0b, 0x45, 0x21, 0x1e, 0xc6, + 0xd0, 0x7f, 0xd3, 0xe0, 0xe2, 0xa1, 0x7b, 0xf1, 0x1f, 0x54, 0x1f, 0xcb, 0x57, 0xdf, 0x8d, 0x13, + 0xa9, 0xbe, 0xd1, 0x65, 0xf7, 0x43, 0xf9, 0x6f, 0x42, 0x95, 0xf5, 0x46, 0x60, 0xda, 0x8f, 0x6f, + 0x52, 0x15, 0xeb, 0xd5, 0xe3, 0x16, 0x8f, 0xf0, 0x35, 0x67, 0xc5, 0x55, 0x97, 0x7c, 0xe2, 0x14, + 0x15, 0x7d, 0x01, 0x0b, 0x72, 0x6b, 0xaf, 0x7b, 0xae, 0x00, 0x60, 0x6e, 0x18, 0xcf, 0x0b, 0xff, + 0xa0, 0x82, 0xce, 0x0e, 0xfa, 0x8d, 0x85, 0xf5, 0x02, 0x2c, 0x1e, 0x22, 0x42, 0x5d, 0xa8, 0xa4, + 0x15, 0x10, 0x0f, 0x98, 0x6f, 0xbd, 0x42, 0xca, 0x3d, 0xd7, 0xfc, 0x9f, 0xca, 0x71, 0x25, 0x95, + 0x71, 0x9c, 0x85, 0x47, 0xf7, 0x61, 0x76, 0x97, 0xb0, 0x6e, 0x2f, 0xa0, 0x6a, 0x74, 0x2b, 0xcb, + 0x03, 0xfc, 0x9a, 0x18, 0xab, 0x6e, 0x65, 0x15, 0x07, 0xfd, 0x46, 0x35, 0x27, 0x90, 0xe3, 0x5b, + 0xde, 0x19, 0x3d, 0xd5, 0x60, 0x81, 0xe4, 0x1f, 0x40, 0xbc, 0x76, 0x4a, 0x46, 0xf0, 0xde, 0x31, + 0x22, 0x28, 0xbc, 0xa1, 0xcc, 0x9a, 0x0a, 0x63, 0xa1, 0xa0, 0xe0, 0x78, 0x88, 0x4d, 0xff, 0x71, + 0x12, 0x1a, 0x47, 0x5c, 0x73, 0xe8, 0x2e, 0x20, 0x6f, 0x87, 0xd3, 0x60, 0x8f, 0xda, 0xb7, 0xa3, + 0x17, 0x5c, 0x3c, 0x87, 0x95, 0xd2, 0xd1, 0x63, 0x63, 0xc8, 0x02, 0x8f, 0xf0, 0x42, 0x0e, 0xcc, + 0x84, 0x99, 0xa9, 0xe8, 0x38, 0x73, 0xa5, 0x8a, 0x36, 0x3b, 0x54, 0x99, 0x0b, 0x83, 0x7e, 0x23, + 0x37, 0x66, 0xe1, 0x1c, 0x3c, 0xb2, 0x00, 0x2c, 0xcf, 0xb5, 0x59, 0xb6, 0x38, 0x9a, 0xe3, 0x1d, + 0xf5, 0xeb, 0xb1, 0x5f, 0xda, 0x9e, 0x13, 0x11, 0xc7, 0x19, 0x58, 0xfd, 0x4f, 0x0d, 0x20, 0xad, + 0x18, 0x74, 0x09, 0x20, 0xf3, 0x3c, 0x8d, 0x3a, 0x7c, 0x59, 0x40, 0xe0, 0x8c, 0x5c, 0xbc, 0x21, + 0x1d, 0xca, 0x39, 0x69, 0xc5, 0xe3, 0x64, 0xf2, 0x86, 0x5c, 0x8f, 0xc4, 0x38, 0xd6, 0xa3, 0x6d, + 0x38, 0x1d, 0x50, 0xc2, 0x3d, 0x57, 0xbd, 0x36, 0x3f, 0x10, 0x23, 0x07, 0x96, 0x92, 0x83, 0x7e, + 0x63, 0x65, 0x9c, 0x37, 0xbe, 0xa1, 0x26, 0x14, 0xe9, 0x84, 0x15, 0x1c, 0xba, 0x0d, 0x55, 0xc5, + 0x91, 0x59, 0x70, 0x54, 0xd1, 0x17, 0xd4, 0x6a, 0xaa, 0xeb, 0x45, 0x03, 0x3c, 0xec, 0x63, 0x6e, + 0x3c, 0x7b, 0x59, 0x9f, 0x78, 0xfe, 0xb2, 0x3e, 0xf1, 0xe2, 0x65, 0x7d, 0xe2, 0xe9, 0xa0, 0xae, + 0x3d, 0x1b, 0xd4, 0xb5, 0xe7, 0x83, 0xba, 0xf6, 0x62, 0x50, 0xd7, 0x7e, 0x19, 0xd4, 0xb5, 0x6f, + 0x7f, 0xad, 0x4f, 0x7c, 0xbc, 0x3c, 0xf6, 0xff, 0x2a, 0x7f, 0x05, 0x00, 0x00, 0xff, 0xff, 0xc3, + 0xd9, 0x66, 0xdd, 0x9c, 0x11, 0x00, 0x00, } func (m *AuditAnnotation) Marshal() (dAtA []byte, err error) { @@ -511,6 +610,39 @@ func (m *AuditAnnotation) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *ExpressionWarning) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ExpressionWarning) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ExpressionWarning) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.Warning) + copy(dAtA[i:], m.Warning) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Warning))) + i-- + dAtA[i] = 0x1a + i -= len(m.FieldRef) + copy(dAtA[i:], m.FieldRef) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.FieldRef))) + i-- + dAtA[i] = 0x12 + return len(dAtA) - i, nil +} + func (m *MatchResources) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -701,6 +833,43 @@ func (m *ParamRef) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *TypeChecking) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TypeChecking) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TypeChecking) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ExpressionWarnings) > 0 { + for iNdEx := len(m.ExpressionWarnings) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ExpressionWarnings[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func (m *ValidatingAdmissionPolicy) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -721,6 +890,16 @@ func (m *ValidatingAdmissionPolicy) MarshalToSizedBuffer(dAtA []byte) (int, erro _ = i var l int _ = l + { + size, err := m.Status.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a { size, err := m.Spec.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -1024,6 +1203,58 @@ func (m *ValidatingAdmissionPolicySpec) MarshalToSizedBuffer(dAtA []byte) (int, return len(dAtA) - i, nil } +func (m *ValidatingAdmissionPolicyStatus) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ValidatingAdmissionPolicyStatus) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ValidatingAdmissionPolicyStatus) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Conditions) > 0 { + for iNdEx := len(m.Conditions) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Conditions[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if m.TypeChecking != nil { + { + size, err := m.TypeChecking.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + i = encodeVarintGenerated(dAtA, i, uint64(m.ObservedGeneration)) + i-- + dAtA[i] = 0x8 + return len(dAtA) - i, nil +} + func (m *Validation) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -1093,6 +1324,19 @@ func (m *AuditAnnotation) Size() (n int) { return n } +func (m *ExpressionWarning) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.FieldRef) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Warning) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + func (m *MatchResources) Size() (n int) { if m == nil { return 0 @@ -1169,6 +1413,21 @@ func (m *ParamRef) Size() (n int) { return n } +func (m *TypeChecking) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.ExpressionWarnings) > 0 { + for _, e := range m.ExpressionWarnings { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } + return n +} + func (m *ValidatingAdmissionPolicy) Size() (n int) { if m == nil { return 0 @@ -1179,6 +1438,8 @@ func (m *ValidatingAdmissionPolicy) Size() (n int) { n += 1 + l + sovGenerated(uint64(l)) l = m.Spec.Size() n += 1 + l + sovGenerated(uint64(l)) + l = m.Status.Size() + n += 1 + l + sovGenerated(uint64(l)) return n } @@ -1287,6 +1548,26 @@ func (m *ValidatingAdmissionPolicySpec) Size() (n int) { return n } +func (m *ValidatingAdmissionPolicyStatus) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += 1 + sovGenerated(uint64(m.ObservedGeneration)) + if m.TypeChecking != nil { + l = m.TypeChecking.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + if len(m.Conditions) > 0 { + for _, e := range m.Conditions { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } + return n +} + func (m *Validation) Size() (n int) { if m == nil { return 0 @@ -1323,6 +1604,17 @@ func (this *AuditAnnotation) String() string { }, "") return s } +func (this *ExpressionWarning) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&ExpressionWarning{`, + `FieldRef:` + fmt.Sprintf("%v", this.FieldRef) + `,`, + `Warning:` + fmt.Sprintf("%v", this.Warning) + `,`, + `}`, + }, "") + return s +} func (this *MatchResources) String() string { if this == nil { return "nil" @@ -1380,6 +1672,21 @@ func (this *ParamRef) String() string { }, "") return s } +func (this *TypeChecking) String() string { + if this == nil { + return "nil" + } + repeatedStringForExpressionWarnings := "[]ExpressionWarning{" + for _, f := range this.ExpressionWarnings { + repeatedStringForExpressionWarnings += strings.Replace(strings.Replace(f.String(), "ExpressionWarning", "ExpressionWarning", 1), `&`, ``, 1) + "," + } + repeatedStringForExpressionWarnings += "}" + s := strings.Join([]string{`&TypeChecking{`, + `ExpressionWarnings:` + repeatedStringForExpressionWarnings + `,`, + `}`, + }, "") + return s +} func (this *ValidatingAdmissionPolicy) String() string { if this == nil { return "nil" @@ -1387,6 +1694,7 @@ func (this *ValidatingAdmissionPolicy) String() string { s := strings.Join([]string{`&ValidatingAdmissionPolicy{`, `ObjectMeta:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ObjectMeta), "ObjectMeta", "v1.ObjectMeta", 1), `&`, ``, 1) + `,`, `Spec:` + strings.Replace(strings.Replace(this.Spec.String(), "ValidatingAdmissionPolicySpec", "ValidatingAdmissionPolicySpec", 1), `&`, ``, 1) + `,`, + `Status:` + strings.Replace(strings.Replace(this.Status.String(), "ValidatingAdmissionPolicyStatus", "ValidatingAdmissionPolicyStatus", 1), `&`, ``, 1) + `,`, `}`, }, "") return s @@ -1471,6 +1779,23 @@ func (this *ValidatingAdmissionPolicySpec) String() string { }, "") return s } +func (this *ValidatingAdmissionPolicyStatus) String() string { + if this == nil { + return "nil" + } + repeatedStringForConditions := "[]Condition{" + for _, f := range this.Conditions { + repeatedStringForConditions += fmt.Sprintf("%v", f) + "," + } + repeatedStringForConditions += "}" + s := strings.Join([]string{`&ValidatingAdmissionPolicyStatus{`, + `ObservedGeneration:` + fmt.Sprintf("%v", this.ObservedGeneration) + `,`, + `TypeChecking:` + strings.Replace(this.TypeChecking.String(), "TypeChecking", "TypeChecking", 1) + `,`, + `Conditions:` + repeatedStringForConditions + `,`, + `}`, + }, "") + return s +} func (this *Validation) String() string { if this == nil { return "nil" @@ -1606,6 +1931,120 @@ func (m *AuditAnnotation) Unmarshal(dAtA []byte) error { } return nil } +func (m *ExpressionWarning) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ExpressionWarning: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ExpressionWarning: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FieldRef", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FieldRef = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Warning", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Warning = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *MatchResources) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -2172,6 +2611,90 @@ func (m *ParamRef) Unmarshal(dAtA []byte) error { } return nil } +func (m *TypeChecking) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TypeChecking: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TypeChecking: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ExpressionWarnings", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ExpressionWarnings = append(m.ExpressionWarnings, ExpressionWarning{}) + if err := m.ExpressionWarnings[len(m.ExpressionWarnings)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *ValidatingAdmissionPolicy) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -2267,6 +2790,39 @@ func (m *ValidatingAdmissionPolicy) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Status.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -3047,6 +3603,145 @@ func (m *ValidatingAdmissionPolicySpec) Unmarshal(dAtA []byte) error { } return nil } +func (m *ValidatingAdmissionPolicyStatus) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ValidatingAdmissionPolicyStatus: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ValidatingAdmissionPolicyStatus: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ObservedGeneration", wireType) + } + m.ObservedGeneration = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ObservedGeneration |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TypeChecking", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.TypeChecking == nil { + m.TypeChecking = &TypeChecking{} + } + if err := m.TypeChecking.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Conditions", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Conditions = append(m.Conditions, v1.Condition{}) + if err := m.Conditions[len(m.Conditions)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *Validation) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/staging/src/k8s.io/api/admissionregistration/v1alpha1/generated.proto b/staging/src/k8s.io/api/admissionregistration/v1alpha1/generated.proto index 3084be4fead..6348472d65f 100644 --- a/staging/src/k8s.io/api/admissionregistration/v1alpha1/generated.proto +++ b/staging/src/k8s.io/api/admissionregistration/v1alpha1/generated.proto @@ -66,6 +66,19 @@ message AuditAnnotation { 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 // on whether it meets the match criteria. // 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; } +// 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. message ValidatingAdmissionPolicy { // 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. 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. @@ -353,6 +382,24 @@ message ValidatingAdmissionPolicySpec { 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. message Validation { // Expression represents the expression which will be evaluated by CEL. diff --git a/staging/src/k8s.io/api/admissionregistration/v1alpha1/types.go b/staging/src/k8s.io/api/admissionregistration/v1alpha1/types.go index 299751c0210..ec7a1301783 100644 --- a/staging/src/k8s.io/api/admissionregistration/v1alpha1/types.go +++ b/staging/src/k8s.io/api/admissionregistration/v1alpha1/types.go @@ -74,6 +74,49 @@ type ValidatingAdmissionPolicy struct { metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` // Specification of the desired behavior of the ValidatingAdmissionPolicy. 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 diff --git a/staging/src/k8s.io/api/admissionregistration/v1alpha1/types_swagger_doc_generated.go b/staging/src/k8s.io/api/admissionregistration/v1alpha1/types_swagger_doc_generated.go index 1cd597eb424..5117fb9b18e 100644 --- a/staging/src/k8s.io/api/admissionregistration/v1alpha1/types_swagger_doc_generated.go +++ b/staging/src/k8s.io/api/admissionregistration/v1alpha1/types_swagger_doc_generated.go @@ -37,6 +37,16 @@ func (AuditAnnotation) SwaggerDoc() map[string]string { 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{ "": "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.", @@ -79,10 +89,20 @@ func (ParamRef) SwaggerDoc() map[string]string { 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{ "": "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.", "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 { @@ -144,6 +164,17 @@ func (ValidatingAdmissionPolicySpec) SwaggerDoc() map[string]string { 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{ "": "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.", diff --git a/staging/src/k8s.io/api/admissionregistration/v1alpha1/zz_generated.deepcopy.go b/staging/src/k8s.io/api/admissionregistration/v1alpha1/zz_generated.deepcopy.go index aa60c491f05..65842ed2469 100644 --- a/staging/src/k8s.io/api/admissionregistration/v1alpha1/zz_generated.deepcopy.go +++ b/staging/src/k8s.io/api/admissionregistration/v1alpha1/zz_generated.deepcopy.go @@ -42,6 +42,22 @@ func (in *AuditAnnotation) DeepCopy() *AuditAnnotation { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExpressionWarning) DeepCopyInto(out *ExpressionWarning) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExpressionWarning. +func (in *ExpressionWarning) DeepCopy() *ExpressionWarning { + if in == nil { + return nil + } + out := new(ExpressionWarning) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MatchResources) DeepCopyInto(out *MatchResources) { *out = *in @@ -141,12 +157,34 @@ func (in *ParamRef) DeepCopy() *ParamRef { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TypeChecking) DeepCopyInto(out *TypeChecking) { + *out = *in + if in.ExpressionWarnings != nil { + in, out := &in.ExpressionWarnings, &out.ExpressionWarnings + *out = make([]ExpressionWarning, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TypeChecking. +func (in *TypeChecking) DeepCopy() *TypeChecking { + if in == nil { + return nil + } + out := new(TypeChecking) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ValidatingAdmissionPolicy) DeepCopyInto(out *ValidatingAdmissionPolicy) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) return } @@ -335,6 +373,34 @@ func (in *ValidatingAdmissionPolicySpec) DeepCopy() *ValidatingAdmissionPolicySp return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ValidatingAdmissionPolicyStatus) DeepCopyInto(out *ValidatingAdmissionPolicyStatus) { + *out = *in + if in.TypeChecking != nil { + in, out := &in.TypeChecking, &out.TypeChecking + *out = new(TypeChecking) + (*in).DeepCopyInto(*out) + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ValidatingAdmissionPolicyStatus. +func (in *ValidatingAdmissionPolicyStatus) DeepCopy() *ValidatingAdmissionPolicyStatus { + if in == nil { + return nil + } + out := new(ValidatingAdmissionPolicyStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Validation) DeepCopyInto(out *Validation) { *out = *in diff --git a/staging/src/k8s.io/api/testdata/HEAD/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.json b/staging/src/k8s.io/api/testdata/HEAD/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.json index 1aeb652c492..7b673ce921c 100644 --- a/staging/src/k8s.io/api/testdata/HEAD/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.json +++ b/staging/src/k8s.io/api/testdata/HEAD/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.json @@ -134,5 +134,26 @@ "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" + } + ] } } \ No newline at end of file diff --git a/staging/src/k8s.io/api/testdata/HEAD/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.pb b/staging/src/k8s.io/api/testdata/HEAD/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.pb index 86a25cb59fa..ba3b1f53d8d 100644 Binary files a/staging/src/k8s.io/api/testdata/HEAD/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.pb and b/staging/src/k8s.io/api/testdata/HEAD/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.pb differ diff --git a/staging/src/k8s.io/api/testdata/HEAD/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.yaml b/staging/src/k8s.io/api/testdata/HEAD/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.yaml index 82207627cd1..11373c659d1 100644 --- a/staging/src/k8s.io/api/testdata/HEAD/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.yaml +++ b/staging/src/k8s.io/api/testdata/HEAD/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.yaml @@ -87,3 +87,16 @@ spec: message: messageValue messageExpression: messageExpressionValue 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 diff --git a/staging/src/k8s.io/api/testdata/v1.26.0/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.after_roundtrip.json b/staging/src/k8s.io/api/testdata/v1.26.0/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.after_roundtrip.json new file mode 100644 index 00000000000..ecbc63e1906 --- /dev/null +++ b/staging/src/k8s.io/api/testdata/v1.26.0/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.after_roundtrip.json @@ -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": {} +} \ No newline at end of file diff --git a/staging/src/k8s.io/api/testdata/v1.26.0/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.after_roundtrip.pb b/staging/src/k8s.io/api/testdata/v1.26.0/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.after_roundtrip.pb index b3ff600da14..fec819f1fe3 100644 Binary files a/staging/src/k8s.io/api/testdata/v1.26.0/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.after_roundtrip.pb and b/staging/src/k8s.io/api/testdata/v1.26.0/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.after_roundtrip.pb differ diff --git a/staging/src/k8s.io/api/testdata/v1.26.0/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.after_roundtrip.yaml b/staging/src/k8s.io/api/testdata/v1.26.0/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.after_roundtrip.yaml new file mode 100644 index 00000000000..2e046b95b42 --- /dev/null +++ b/staging/src/k8s.io/api/testdata/v1.26.0/admissionregistration.k8s.io.v1alpha1.ValidatingAdmissionPolicy.after_roundtrip.yaml @@ -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: {} diff --git a/staging/src/k8s.io/apiserver/pkg/admission/initializer/interfaces.go b/staging/src/k8s.io/apiserver/pkg/admission/initializer/interfaces.go index 2a6632c3ed0..6077c89de84 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/initializer/interfaces.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/initializer/interfaces.go @@ -20,6 +20,7 @@ import ( "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/authorization/authorizer" + "k8s.io/apiserver/pkg/cel/openapi/resolver" quota "k8s.io/apiserver/pkg/quota/v1" "k8s.io/client-go/dynamic" "k8s.io/client-go/informers" @@ -81,3 +82,10 @@ type WantsRESTMapper interface { SetRESTMapper(meta.RESTMapper) 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 +} diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/cel/compile.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/cel/compile.go index e3327faaec3..bb122de5faf 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/cel/compile.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/cel/compile.go @@ -81,7 +81,7 @@ func buildRequiredVarsEnv() (*cel.Env, error) { var propDecls []cel.EnvOption reg := apiservercel.NewRegistry(baseEnv) - requestType := buildRequestType() + requestType := BuildRequestType() rt, err := apiservercel.NewRuleTypes(requestType.TypeName(), requestType, reg) if err != nil { return nil, err @@ -134,11 +134,11 @@ func buildWithOptionalVarsEnvs(requiredVarsEnv *cel.Env) (envs, error) { 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. // 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. -func buildRequestType() *apiservercel.DeclType { +func BuildRequestType() *apiservercel.DeclType { field := func(name string, declType *apiservercel.DeclType, required bool) *apiservercel.DeclField { return apiservercel.NewDeclField(name, declType, required, nil, nil) } diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/admission.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/admission.go index c0ca270d84a..9a514b46319 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/admission.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/admission.go @@ -24,6 +24,7 @@ import ( "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apiserver/pkg/authorization/authorizer" + "k8s.io/apiserver/pkg/cel/openapi/resolver" "k8s.io/apiserver/pkg/features" "k8s.io/client-go/dynamic" "k8s.io/component-base/featuregate" @@ -73,6 +74,7 @@ type celAdmissionPlugin struct { dynamicClient dynamic.Interface stopCh <-chan struct{} authorizer authorizer.Authorizer + schemaResolver resolver.SchemaResolver } var _ initializer.WantsExternalKubeInformerFactory = &celAdmissionPlugin{} @@ -81,7 +83,7 @@ var _ initializer.WantsRESTMapper = &celAdmissionPlugin{} var _ initializer.WantsDynamicClient = &celAdmissionPlugin{} var _ initializer.WantsDrainedNotification = &celAdmissionPlugin{} var _ initializer.WantsAuthorizer = &celAdmissionPlugin{} - +var _ initializer.WantsSchemaResolver = &celAdmissionPlugin{} var _ admission.InitializationValidator = &celAdmissionPlugin{} var _ admission.ValidationInterface = &celAdmissionPlugin{} @@ -115,6 +117,10 @@ func (c *celAdmissionPlugin) SetAuthorizer(authorizer authorizer.Authorizer) { c.authorizer = authorizer } +func (c *celAdmissionPlugin) SetSchemaResolver(resolver resolver.SchemaResolver) { + c.schemaResolver = resolver +} + func (c *celAdmissionPlugin) InspectFeatureGates(featureGates featuregate.FeatureGate) { if featureGates.Enabled(features.ValidatingAdmissionPolicy) { c.enabled = true @@ -148,7 +154,7 @@ func (c *celAdmissionPlugin) ValidateInitialization() error { if c.authorizer == nil { 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 { return err } diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/controller.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/controller.go index b4dea874188..f54f1acb36f 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/controller.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/controller.go @@ -43,6 +43,7 @@ import ( "k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/matching" celconfig "k8s.io/apiserver/pkg/apis/cel" "k8s.io/apiserver/pkg/authorization/authorizer" + "k8s.io/apiserver/pkg/cel/openapi/resolver" "k8s.io/apiserver/pkg/warning" "k8s.io/client-go/dynamic" "k8s.io/client-go/informers" @@ -124,15 +125,21 @@ func NewAdmissionController( informerFactory informers.SharedInformerFactory, client kubernetes.Interface, restMapper meta.RESTMapper, + schemaResolver resolver.SchemaResolver, dynamicClient dynamic.Interface, authz authorizer.Authorizer, ) CELPolicyEvaluator { + var typeChecker *TypeChecker + if schemaResolver != nil { + typeChecker = &TypeChecker{schemaResolver: schemaResolver, restMapper: restMapper} + } return &celAdmissionController{ definitions: atomic.Value{}, policyController: newPolicyController( restMapper, client, dynamicClient, + typeChecker, cel.NewFilterCompiler(), NewMatcher(matching.NewMatcher(informerFactory.Core().V1().Namespaces().Lister(), client)), generic.NewInformer[*v1alpha1.ValidatingAdmissionPolicy]( diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/controller_reconcile.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/controller_reconcile.go index 62ab0c060d5..4d2671c0829 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/controller_reconcile.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/controller_reconcile.go @@ -27,8 +27,10 @@ import ( corev1 "k8s.io/api/core/v1" apiequality "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/sets" celmetrics "k8s.io/apiserver/pkg/admission/cel" "k8s.io/apiserver/pkg/admission/plugin/cel" @@ -59,6 +61,11 @@ type policyController struct { 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: // - cachedPolicies // - paramCRDControllers @@ -98,6 +105,7 @@ func newPolicyController( restMapper meta.RESTMapper, client kubernetes.Interface, dynamicClient dynamic.Interface, + typeChecker *TypeChecker, filterCompiler cel.FilterCompiler, matcher Matcher, policiesInformer generic.Informer[*v1alpha1.ValidatingAdmissionPolicy], @@ -107,6 +115,7 @@ func newPolicyController( res := &policyController{} *res = policyController{ filterCompiler: filterCompiler, + typeChecker: typeChecker, definitionInfo: make(map[namespacedName]*definitionInfo), bindingInfos: make(map[namespacedName]*bindingInfo), 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 { c.mutex.Lock() 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 // Namespace for policydefinition is empty. @@ -423,6 +442,30 @@ func (c *policyController) reconcilePolicyBinding(namespace, name string, bindin 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 { // Do nothing. // When we add informational type checking we will need to compile in the diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/typechecking.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/typechecking.go new file mode 100644 index 00000000000..7b128e38185 --- /dev/null +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/typechecking.go @@ -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 diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/typechecking_test.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/typechecking_test.go new file mode 100644 index 00000000000..9a3682942d3 --- /dev/null +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy/typechecking_test.go @@ -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) diff --git a/staging/src/k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1/expressionwarning.go b/staging/src/k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1/expressionwarning.go new file mode 100644 index 00000000000..f8b511f512b --- /dev/null +++ b/staging/src/k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1/expressionwarning.go @@ -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 +} diff --git a/staging/src/k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1/typechecking.go b/staging/src/k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1/typechecking.go new file mode 100644 index 00000000000..42a91707105 --- /dev/null +++ b/staging/src/k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1/typechecking.go @@ -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 +} diff --git a/staging/src/k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1/validatingadmissionpolicy.go b/staging/src/k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1/validatingadmissionpolicy.go index 3a23e0c7268..c860b85cf74 100644 --- a/staging/src/k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1/validatingadmissionpolicy.go +++ b/staging/src/k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1/validatingadmissionpolicy.go @@ -32,7 +32,8 @@ import ( type ValidatingAdmissionPolicyApplyConfiguration struct { v1.TypeMetaApplyConfiguration `json:",inline"` *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 @@ -245,3 +246,11 @@ func (b *ValidatingAdmissionPolicyApplyConfiguration) WithSpec(value *Validating b.Spec = value 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 +} diff --git a/staging/src/k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1/validatingadmissionpolicystatus.go b/staging/src/k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1/validatingadmissionpolicystatus.go new file mode 100644 index 00000000000..821184c8a85 --- /dev/null +++ b/staging/src/k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1/validatingadmissionpolicystatus.go @@ -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 +} diff --git a/staging/src/k8s.io/client-go/applyconfigurations/internal/internal.go b/staging/src/k8s.io/client-go/applyconfigurations/internal/internal.go index 1dd82912e6f..6d14312d858 100644 --- a/staging/src/k8s.io/client-go/applyconfigurations/internal/internal.go +++ b/staging/src/k8s.io/client-go/applyconfigurations/internal/internal.go @@ -236,6 +236,17 @@ var schemaYAML = typed.YAMLObject(`types: type: scalar: string 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 map: fields: @@ -318,6 +329,15 @@ var schemaYAML = typed.YAMLObject(`types: type: scalar: string 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 map: fields: @@ -335,6 +355,10 @@ var schemaYAML = typed.YAMLObject(`types: type: namedType: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicySpec default: {} + - name: status + type: + namedType: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyStatus + default: {} - name: io.k8s.api.admissionregistration.v1alpha1.ValidatingAdmissionPolicyBinding map: fields: @@ -394,6 +418,23 @@ var schemaYAML = typed.YAMLObject(`types: elementType: namedType: io.k8s.api.admissionregistration.v1alpha1.Validation 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 map: fields: diff --git a/staging/src/k8s.io/client-go/applyconfigurations/utils.go b/staging/src/k8s.io/client-go/applyconfigurations/utils.go index 81489fa3523..2d8b1daad5f 100644 --- a/staging/src/k8s.io/client-go/applyconfigurations/utils.go +++ b/staging/src/k8s.io/client-go/applyconfigurations/utils.go @@ -141,6 +141,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} { // Group=admissionregistration.k8s.io, Version=v1alpha1 case v1alpha1.SchemeGroupVersion.WithKind("AuditAnnotation"): return &admissionregistrationv1alpha1.AuditAnnotationApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ExpressionWarning"): + return &admissionregistrationv1alpha1.ExpressionWarningApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("MatchResources"): return &admissionregistrationv1alpha1.MatchResourcesApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("NamedRuleWithOperations"): @@ -149,6 +151,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &admissionregistrationv1alpha1.ParamKindApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("ParamRef"): return &admissionregistrationv1alpha1.ParamRefApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("TypeChecking"): + return &admissionregistrationv1alpha1.TypeCheckingApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("ValidatingAdmissionPolicy"): return &admissionregistrationv1alpha1.ValidatingAdmissionPolicyApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("ValidatingAdmissionPolicyBinding"): @@ -157,6 +161,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &admissionregistrationv1alpha1.ValidatingAdmissionPolicyBindingSpecApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("ValidatingAdmissionPolicySpec"): return &admissionregistrationv1alpha1.ValidatingAdmissionPolicySpecApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("ValidatingAdmissionPolicyStatus"): + return &admissionregistrationv1alpha1.ValidatingAdmissionPolicyStatusApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("Validation"): return &admissionregistrationv1alpha1.ValidationApplyConfiguration{} diff --git a/staging/src/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/fake/fake_validatingadmissionpolicy.go b/staging/src/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/fake/fake_validatingadmissionpolicy.go index 38d7713d946..f4358ce46cc 100644 --- a/staging/src/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/fake/fake_validatingadmissionpolicy.go +++ b/staging/src/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/fake/fake_validatingadmissionpolicy.go @@ -98,6 +98,17 @@ func (c *FakeValidatingAdmissionPolicies) Update(ctx context.Context, validating 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. func (c *FakeValidatingAdmissionPolicies) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. @@ -143,3 +154,25 @@ func (c *FakeValidatingAdmissionPolicies) Apply(ctx context.Context, validatingA } 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 +} diff --git a/staging/src/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/validatingadmissionpolicy.go b/staging/src/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/validatingadmissionpolicy.go index ba827f3c99d..1d994b5abf7 100644 --- a/staging/src/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/validatingadmissionpolicy.go +++ b/staging/src/k8s.io/client-go/kubernetes/typed/admissionregistration/v1alpha1/validatingadmissionpolicy.go @@ -43,6 +43,7 @@ type ValidatingAdmissionPoliciesGetter interface { type ValidatingAdmissionPolicyInterface interface { 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) + UpdateStatus(ctx context.Context, validatingAdmissionPolicy *v1alpha1.ValidatingAdmissionPolicy, opts v1.UpdateOptions) (*v1alpha1.ValidatingAdmissionPolicy, error) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) 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) 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) + ApplyStatus(ctx context.Context, validatingAdmissionPolicy *admissionregistrationv1alpha1.ValidatingAdmissionPolicyApplyConfiguration, opts v1.ApplyOptions) (result *v1alpha1.ValidatingAdmissionPolicy, err error) ValidatingAdmissionPolicyExpansion } @@ -132,6 +134,21 @@ func (c *validatingAdmissionPolicies) Update(ctx context.Context, validatingAdmi 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. func (c *validatingAdmissionPolicies) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { return c.client.Delete(). @@ -195,3 +212,32 @@ func (c *validatingAdmissionPolicies) Apply(ctx context.Context, validatingAdmis Into(result) 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 +} diff --git a/staging/src/k8s.io/cloud-provider/go.mod b/staging/src/k8s.io/cloud-provider/go.mod index 0b177dd692a..123d570bb51 100644 --- a/staging/src/k8s.io/cloud-provider/go.mod +++ b/staging/src/k8s.io/cloud-provider/go.mod @@ -24,6 +24,7 @@ require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/NYTimes/gziphandler v1.1.1 // 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/blang/semver/v4 v4.0.0 // 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/mailru/easyjson v0.7.7 // 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/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect diff --git a/staging/src/k8s.io/cloud-provider/go.sum b/staging/src/k8s.io/cloud-provider/go.sum index f1e0f2bdc38..8f16ef9634b 100644 --- a/staging/src/k8s.io/cloud-provider/go.sum +++ b/staging/src/k8s.io/cloud-provider/go.sum @@ -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/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/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/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 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.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM= 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/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= diff --git a/staging/src/k8s.io/controller-manager/go.mod b/staging/src/k8s.io/controller-manager/go.mod index b3bc2c36310..2da1e1b38a2 100644 --- a/staging/src/k8s.io/controller-manager/go.mod +++ b/staging/src/k8s.io/controller-manager/go.mod @@ -20,6 +20,7 @@ require ( require ( github.com/NYTimes/gziphandler v1.1.1 // 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/blang/semver/v4 v4.0.0 // 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/mailru/easyjson v0.7.7 // 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/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect diff --git a/staging/src/k8s.io/controller-manager/go.sum b/staging/src/k8s.io/controller-manager/go.sum index d71cc14c35b..d774038e4fd 100644 --- a/staging/src/k8s.io/controller-manager/go.sum +++ b/staging/src/k8s.io/controller-manager/go.sum @@ -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/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/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/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 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.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM= 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-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= diff --git a/staging/src/k8s.io/kube-aggregator/go.mod b/staging/src/k8s.io/kube-aggregator/go.mod index e784e9dced0..daa324446a4 100644 --- a/staging/src/k8s.io/kube-aggregator/go.mod +++ b/staging/src/k8s.io/kube-aggregator/go.mod @@ -28,6 +28,7 @@ require ( require ( github.com/NYTimes/gziphandler v1.1.1 // 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/blang/semver/v4 v4.0.0 // 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/mailru/easyjson v0.7.7 // 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/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect diff --git a/staging/src/k8s.io/kube-aggregator/go.sum b/staging/src/k8s.io/kube-aggregator/go.sum index 26ad4cf6302..23722bcc172 100644 --- a/staging/src/k8s.io/kube-aggregator/go.sum +++ b/staging/src/k8s.io/kube-aggregator/go.sum @@ -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/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/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/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 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.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM= 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-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= diff --git a/staging/src/k8s.io/pod-security-admission/go.mod b/staging/src/k8s.io/pod-security-admission/go.mod index 8a5e6abee98..c6db05a5b34 100644 --- a/staging/src/k8s.io/pod-security-admission/go.mod +++ b/staging/src/k8s.io/pod-security-admission/go.mod @@ -23,6 +23,7 @@ require ( require ( github.com/NYTimes/gziphandler v1.1.1 // 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/cenkalti/backoff/v4 v4.1.3 // 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/mailru/easyjson v0.7.7 // 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/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect diff --git a/staging/src/k8s.io/pod-security-admission/go.sum b/staging/src/k8s.io/pod-security-admission/go.sum index 0fcd32f62e3..4f4f5413454 100644 --- a/staging/src/k8s.io/pod-security-admission/go.sum +++ b/staging/src/k8s.io/pod-security-admission/go.sum @@ -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/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/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/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 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.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM= 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-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= diff --git a/staging/src/k8s.io/sample-apiserver/go.mod b/staging/src/k8s.io/sample-apiserver/go.mod index 963520fc0a8..3943a30a9e0 100644 --- a/staging/src/k8s.io/sample-apiserver/go.mod +++ b/staging/src/k8s.io/sample-apiserver/go.mod @@ -20,6 +20,7 @@ require ( require ( github.com/NYTimes/gziphandler v1.1.1 // 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/blang/semver/v4 v4.0.0 // 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/mailru/easyjson v0.7.7 // 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/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect diff --git a/staging/src/k8s.io/sample-apiserver/go.sum b/staging/src/k8s.io/sample-apiserver/go.sum index d186ab1b516..96997635f17 100644 --- a/staging/src/k8s.io/sample-apiserver/go.sum +++ b/staging/src/k8s.io/sample-apiserver/go.sum @@ -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/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/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/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 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.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM= 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-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= diff --git a/test/integration/apiserver/admissionwebhook/admission_test.go b/test/integration/apiserver/admissionwebhook/admission_test.go index 0fd4af4ad1b..bbf5445c3e9 100644 --- a/test/integration/apiserver/admissionwebhook/admission_test.go +++ b/test/integration/apiserver/admissionwebhook/admission_test.go @@ -138,12 +138,13 @@ var ( // admissionExemptResources lists objects which are exempt from admission validation/mutation, // only resources exempted from admission processing by API server should be listed here. admissionExemptResources = map[schema.GroupVersionResource]bool{ - gvr("admissionregistration.k8s.io", "v1beta1", "mutatingwebhookconfigurations"): true, - gvr("admissionregistration.k8s.io", "v1beta1", "validatingwebhookconfigurations"): true, - gvr("admissionregistration.k8s.io", "v1", "mutatingwebhookconfigurations"): true, - gvr("admissionregistration.k8s.io", "v1", "validatingwebhookconfigurations"): true, - gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicies"): true, - gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicybindings"): true, + gvr("admissionregistration.k8s.io", "v1beta1", "mutatingwebhookconfigurations"): true, + gvr("admissionregistration.k8s.io", "v1beta1", "validatingwebhookconfigurations"): true, + gvr("admissionregistration.k8s.io", "v1", "mutatingwebhookconfigurations"): true, + gvr("admissionregistration.k8s.io", "v1", "validatingwebhookconfigurations"): true, + gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicies"): true, + gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicies/status"): true, + gvr("admissionregistration.k8s.io", "v1alpha1", "validatingadmissionpolicybindings"): true, } parentResources = map[schema.GroupVersionResource]schema.GroupVersionResource{ diff --git a/test/integration/apiserver/apply/reset_fields_test.go b/test/integration/apiserver/apply/reset_fields_test.go index ff4f6d696c9..a76aeb7fd94 100644 --- a/test/integration/apiserver/apply/reset_fields_test.go +++ b/test/integration/apiserver/apply/reset_fields_test.go @@ -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", "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"}]}}`, + // 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 @@ -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", "resourceclaimtemplates"): `{"spec": {"spec": {"resourceClassName": "class2name"}}}`, 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. diff --git a/test/integration/apiserver/apply/status_test.go b/test/integration/apiserver/apply/status_test.go index 8d4593f14d7..b729c8baa6f 100644 --- a/test/integration/apiserver/apply/status_test.go +++ b/test/integration/apiserver/apply/status_test.go @@ -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", "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"}]}}`, + // 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"}]}}` diff --git a/test/integration/apiserver/cel/validatingadmissionpolicy_test.go b/test/integration/apiserver/cel/validatingadmissionpolicy_test.go index 3cb2417cad9..f3e884b01ed 100644 --- a/test/integration/apiserver/cel/validatingadmissionpolicy_test.go +++ b/test/integration/apiserver/cel/validatingadmissionpolicy_test.go @@ -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 - policyCopy := policy.DeepCopy() + policy, err = client.AdmissionregistrationV1alpha1().ValidatingAdmissionPolicies().Get(context.TODO(), policy.Name, metav1.GetOptions{}) + if err != nil { + t.Fatal(err) + } ignoreFailurePolicy := admissionregistrationv1alpha1.Ignore - policyCopy.Spec.FailurePolicy = &ignoreFailurePolicy - _, err = client.AdmissionregistrationV1alpha1().ValidatingAdmissionPolicies().Update(context.TODO(), policyCopy, metav1.UpdateOptions{}) + policy.Spec.FailurePolicy = &ignoreFailurePolicy + _, err = client.AdmissionregistrationV1alpha1().ValidatingAdmissionPolicies().Update(context.TODO(), policy, metav1.UpdateOptions{}) if err != nil { t.Error(err) } @@ -866,9 +869,12 @@ func Test_ValidatingAdmissionPolicy_UpdateParamKind(t *testing.T) { APIVersion: "v1", Kind: "Secret", } - policyCopy := policy.DeepCopy() - policyCopy.Spec.ParamKind = paramKind - _, err = client.AdmissionregistrationV1alpha1().ValidatingAdmissionPolicies().Update(context.TODO(), policyCopy, metav1.UpdateOptions{}) + policy, err = client.AdmissionregistrationV1alpha1().ValidatingAdmissionPolicies().Get(context.TODO(), policy.Name, metav1.GetOptions{}) + if err != nil { + t.Error(err) + } + policy.Spec.ParamKind = paramKind + _, err = client.AdmissionregistrationV1alpha1().ValidatingAdmissionPolicies().Update(context.TODO(), policy, metav1.UpdateOptions{}) if err != nil { t.Error(err) } @@ -2611,6 +2617,26 @@ func withPolicyExistsLabels(labels []string, policy *admissionregistrationv1alph 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 { policy.Spec.Validations = validations return policy @@ -2885,3 +2911,114 @@ rules: 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)) + } + } +}