Documentation
¶
Overview ¶
Package validation holds the predicates which the fleet.yaml validation run by `fleet apply` and the agent code consuming those values have to agree on. A rule which lives in one place cannot drift apart between the two.
It must stay a leaf package: a rule kept here has no fleet-internal dependencies beyond pkg/apis, so both the validator and the agent can import it freely, whatever else either of them already pulls in.
Index ¶
- Variables
- func ForEachBundleSpecOptions(prefix string, spec *fleet.BundleSpec, ...) error
- func InvalidJSONPointerError(value string) error
- func IsJSONPointer(value string) bool
- func IsSupportedPatchOp(op string) bool
- func SupportedPatchOps() []string
- func UnsupportedPatchOpError(op string) error
- func ValidateComparePatchJSONPointers(path string, opts *fleet.BundleDeploymentOptions) error
- func ValidateComparePatchNames(path string, opts *fleet.BundleDeploymentOptions) error
- func ValidateComparePatchOperationPaths(path string, opts *fleet.BundleDeploymentOptions) error
- func ValidateComparePatchOperations(path string, opts *fleet.BundleDeploymentOptions) error
Constants ¶
This section is empty.
Variables ¶
var BundleDeploymentOptionChecks = []func(path string, opts *fleet.BundleDeploymentOptions) error{ ValidateComparePatchNames, ValidateComparePatchOperations, ValidateComparePatchOperationPaths, ValidateComparePatchJSONPointers, }
BundleDeploymentOptionChecks are the rules which apply to a BundleDeploymentOptions whichever entry point it was written at. Both bundlereader.validateFleetYAML and the HelmOp reconciler's validateBundleSpec range over this one list, so a rule added here cannot end up enforced on fleet.yaml but not on a HelmOp, or the other way round.
Each entry takes the field path prefix identifying the options to the user, so the caller decides how paths are reported (see ForEachBundleSpecOptions).
Functions ¶
func ForEachBundleSpecOptions ¶
func ForEachBundleSpecOptions( prefix string, spec *fleet.BundleSpec, fn func(path string, opts *fleet.BundleDeploymentOptions) error, ) error
ForEachBundleSpecOptions calls fn for every BundleDeploymentOptions reachable from a BundleSpec — the spec's own options and those of each target — with the field path prefix which identifies it to the user, below the given prefix.
BundleSpec is what fleet.yaml and a HelmOp have in common, so a rule walked with this function is checked identically on both. Note that TargetCustomizations are *not* part of BundleSpec: a fleet.yaml has that third site and has to walk it itself (see bundlereader.forEachOptions).
func InvalidJSONPointerError ¶
InvalidJSONPointerError returns the error reported for a diff comparePatch pointer IsJSONPointer rejects. It lives here so that the validator and the agent, which both have to explain the same rejection, cannot word it differently.
func IsJSONPointer ¶
IsJSONPointer reports whether value can be used as a JSON pointer by a diff comparePatch — as an operation path or as a jsonPointers entry, which end up in the same json-patch call. A pointer has to be non-empty and start with "/".
The rule is deliberately only what json-patch cannot resolve to what the user wrote. It is not a full RFC 6901 check, because json-patch is laxer than the RFC in a way real configurations depend on — it rewrites "~0" and "~1" and leaves any other "~" sequence alone, so "/spec/a~2b" legitimately addresses a key named "a~2b" and must keep working.
The missing leading slash is not merely a pointer which fails to resolve. Whether it fails depends on how many segments it has, because json-patch splits the path on "/" and then walks split[1:len(split)-1]: "spec.replicas" has one segment and addresses nothing, but "metadata/kind" has two, leaves nothing to walk, and so addresses the key "kind" at the *root* of the document — a patch on it really does rewrite the resource's kind, silently and nowhere near where the user aimed it.
The empty pointer is rejected even though RFC 6901 gives it a meaning (the whole document): Operation.Path is marshalled with omitempty, so an empty path reaches json-patch as a missing "path" field and always fails with "operation missing path field".
func IsSupportedPatchOp ¶
IsSupportedPatchOp reports whether op is an operation Fleet can apply as part of a diff comparePatch. The empty string is not one: an operation without an op is not a no-op, it makes the patch fail.
func SupportedPatchOps ¶
func SupportedPatchOps() []string
SupportedPatchOps returns the operations accepted by IsSupportedPatchOp, sorted, for use in error messages.
func UnsupportedPatchOpError ¶
UnsupportedPatchOpError returns the error reported for a diff comparePatch operation IsSupportedPatchOp rejects. It lives here so that the validator and the agent, which both have to explain the same rejection, cannot word it differently or list different operations.
func ValidateComparePatchJSONPointers ¶
func ValidateComparePatchJSONPointers(path string, opts *fleet.BundleDeploymentOptions) error
ValidateComparePatchJSONPointers checks that every entry of every diff.comparePatches[].jsonPointers in opts is a JSON pointer the agent can address. A malformed entry is dead config, and the most invisible kind Fleet has: the ignore normalizer logs the failure at V(1) info level, which is filtered out at the agent's default verbosity, so nothing is reported at all and the field the user asked to ignore keeps showing up as drift. An entry which json-patch does resolve, but not to what the user wrote, reports nothing either and ignores the wrong field: see IsJSONPointer for the two-segment case.
func ValidateComparePatchNames ¶
func ValidateComparePatchNames(path string, opts *fleet.BundleDeploymentOptions) error
ValidateComparePatchNames checks that every diff.comparePatches[].name in opts compiles as a regular expression. The agent matches a patch by exact name first and falls back to matching the name as a regex, so a name which does not compile is dead config: without this validation, it would fail to compile on the agent and have no effect.
func ValidateComparePatchOperationPaths ¶
func ValidateComparePatchOperationPaths(path string, opts *fleet.BundleDeploymentOptions) error
ValidateComparePatchOperationPaths checks that every diff.comparePatches[].operations[].path in opts is a JSON pointer the agent can address. Anything else is dead config, in one of two ways: usually the agent marshals the operation into a JSON patch whose path json-patch fails to resolve, and because that failure only reaches a log line the patch silently does nothing — taking the other operations held for the same resource with it. Occasionally it is worse than that, because json-patch resolves the path to something the user did not write: see IsJSONPointer for the two-segment case.
An "ignore" operation is skipped: it removes the whole resource from the diff and its path is never read (see desiredset.Diff).
func ValidateComparePatchOperations ¶
func ValidateComparePatchOperations(path string, opts *fleet.BundleDeploymentOptions) error
ValidateComparePatchOperations checks that every diff.comparePatches[].operations[].op in opts names an operation Fleet can apply. Anything else is dead config: the agent marshals the operation into a JSON patch which json-patch then refuses to apply, and that failure is only logged, so the patch does nothing. An empty op is rejected too; it fails in exactly the same way rather than being the no-op it looks like.
Types ¶
This section is empty.