mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-11 17:12:51 +00:00
Merge pull request #2613 from Shell32-Natsu/validator
Introduce `validators` field in kustomization file
This commit is contained in:
@@ -209,6 +209,10 @@ func (kt *KustTarget) accumulateTarget(ra *accumulator.ResAccumulator) (
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
err = kt.runValidators(ra)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
err = ra.MergeVars(kt.kustomization.Vars)
|
err = ra.MergeVars(kt.kustomization.Vars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(
|
return nil, errors.Wrapf(
|
||||||
@@ -260,7 +264,7 @@ func (kt *KustTarget) runTransformers(ra *accumulator.ResAccumulator) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
r = append(r, lts...)
|
r = append(r, lts...)
|
||||||
lts, err = kt.configureExternalTransformers()
|
lts, err = kt.configureExternalTransformers(kt.kustomization.Transformers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -269,15 +273,54 @@ func (kt *KustTarget) runTransformers(ra *accumulator.ResAccumulator) error {
|
|||||||
return ra.Transform(t)
|
return ra.Transform(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (kt *KustTarget) configureExternalTransformers() ([]resmap.Transformer, error) {
|
func (kt *KustTarget) configureExternalTransformers(transformers []string) ([]resmap.Transformer, error) {
|
||||||
ra := accumulator.MakeEmptyAccumulator()
|
ra := accumulator.MakeEmptyAccumulator()
|
||||||
ra, err := kt.accumulateResources(ra, kt.kustomization.Transformers)
|
ra, err := kt.accumulateResources(ra, transformers)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return kt.pLdr.LoadTransformers(kt.ldr, kt.validator, ra.ResMap())
|
return kt.pLdr.LoadTransformers(kt.ldr, kt.validator, ra.ResMap())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (kt *KustTarget) runValidators(ra *accumulator.ResAccumulator) error {
|
||||||
|
validators, err := kt.configureExternalTransformers(kt.kustomization.Validators)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, v := range validators {
|
||||||
|
// Validators shouldn't modify the resource map
|
||||||
|
orignal := ra.ResMap().DeepCopy()
|
||||||
|
err = v.Transform(ra.ResMap())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
new := ra.ResMap().DeepCopy()
|
||||||
|
kt.removeValidatedByLabel(new)
|
||||||
|
if err = orignal.ErrorIfNotEqualSets(new); err != nil {
|
||||||
|
return fmt.Errorf("validator shouldn't modify the resource map: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kt *KustTarget) removeValidatedByLabel(rm resmap.ResMap) {
|
||||||
|
|
||||||
|
resources := rm.Resources()
|
||||||
|
for _, r := range resources {
|
||||||
|
labels := r.GetLabels()
|
||||||
|
if _, found := labels[konfig.ValidatedByLabelKey]; !found {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
delete(labels, konfig.ValidatedByLabelKey)
|
||||||
|
if len(labels) == 0 {
|
||||||
|
r.SetLabels(nil)
|
||||||
|
} else {
|
||||||
|
r.SetLabels(labels)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// accumulateResources fills the given resourceAccumulator
|
// accumulateResources fills the given resourceAccumulator
|
||||||
// with resources read from the given list of paths.
|
// with resources read from the given list of paths.
|
||||||
func (kt *KustTarget) accumulateResources(
|
func (kt *KustTarget) accumulateResources(
|
||||||
|
|||||||
@@ -36,4 +36,7 @@ const (
|
|||||||
|
|
||||||
// An environment variable to turn on/off adding the ManagedByLabelKey
|
// An environment variable to turn on/off adding the ManagedByLabelKey
|
||||||
EnableManagedbyLabelEnv = "KUSTOMIZE_ENABLE_MANAGEDBY_LABEL"
|
EnableManagedbyLabelEnv = "KUSTOMIZE_ENABLE_MANAGEDBY_LABEL"
|
||||||
|
|
||||||
|
// Label key that indicates the resources are validated by a validator
|
||||||
|
ValidatedByLabelKey = "validated-by"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -124,6 +124,9 @@ type Kustomization struct {
|
|||||||
// Transformers is a list of files containing transformers
|
// Transformers is a list of files containing transformers
|
||||||
Transformers []string `json:"transformers,omitempty" yaml:"transformers,omitempty"`
|
Transformers []string `json:"transformers,omitempty" yaml:"transformers,omitempty"`
|
||||||
|
|
||||||
|
// Validators is a list of files containing validators
|
||||||
|
Validators []string `json:"validators,omitempty" yaml:"validators,omitempty"`
|
||||||
|
|
||||||
// Inventory appends an object that contains the record
|
// Inventory appends an object that contains the record
|
||||||
// of all other objects, which can be used in apply, prune and delete
|
// of all other objects, which can be used in apply, prune and delete
|
||||||
Inventory *Inventory `json:"inventory,omitempty" yaml:"inventory,omitempty"`
|
Inventory *Inventory `json:"inventory,omitempty" yaml:"inventory,omitempty"`
|
||||||
|
|||||||
224
examples/validatorPlugin.md
Normal file
224
examples/validatorPlugin.md
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
# Examples for Validator Plugin
|
||||||
|
|
||||||
|
Previously, Kustomize suggested to used a transformer plugin to [perform validation](https://github.com/kubernetes-sigs/kustomize/tree/master/examples/validationTransformer). Now we introduce a new type of plugin: validator. As the name says, validator is used to validate the result YAML output. It works in the same way with *transformers* but cannot *modify* the input YAML content. Let's take a look at how it works.
|
||||||
|
|
||||||
|
## Make a Place to Work
|
||||||
|
|
||||||
|
<!-- @makeWorkplace @validatorPlugin -->
|
||||||
|
```
|
||||||
|
DEMO_HOME=$(mktemp -d)
|
||||||
|
mkdir -p $DEMO_HOME/valid
|
||||||
|
PLUGINDIR=$DEMO_HOME/kustomize/plugin/someteam.example.com/v1/validator
|
||||||
|
mkdir -p $PLUGINDIR
|
||||||
|
```
|
||||||
|
|
||||||
|
## Write a Validator Plugin
|
||||||
|
|
||||||
|
Kustomize has the following assumption of a validator plugin:
|
||||||
|
- The resources are passed to the validator plugin from stdin.
|
||||||
|
- The configuration file for the validator plugin is passed in
|
||||||
|
as the first argument.
|
||||||
|
- The working directory of the plugin is the kustomization
|
||||||
|
directory where it is used as a validator.
|
||||||
|
- The validated resources are written to stdout by the plugin. Or the validator can print nothing to the stdout if there is no need to change the input.
|
||||||
|
- Validator can **only** add a label named `validated-by` (case-sensitive) to the **top-level** resources. If there is any other modification in the validator, Kustomize will throw an error.
|
||||||
|
- If the return code of the transformer plugin is non zero,
|
||||||
|
Kustomize regards there is an error during the validation.
|
||||||
|
|
||||||
|
You can use either exec plugin or Go plugin as a validator. Here we use a bash script as an exec plugin.
|
||||||
|
|
||||||
|
<!-- @writePlugin @validatorPlugin -->
|
||||||
|
```bash
|
||||||
|
cat <<'EOF' > $PLUGINDIR/Validator
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Do whatever you want here. In this example we
|
||||||
|
# just print out the input
|
||||||
|
|
||||||
|
cat
|
||||||
|
|
||||||
|
EOF
|
||||||
|
chmod +x $PLUGINDIR/Validator
|
||||||
|
```
|
||||||
|
|
||||||
|
## Use the Validator Plugin
|
||||||
|
|
||||||
|
Define a kustomization containing a valid ConfigMap
|
||||||
|
and the transformer plugin.
|
||||||
|
|
||||||
|
<!-- @writeKustomization @validatorPlugin -->
|
||||||
|
```bash
|
||||||
|
cat <<'EOF' >$DEMO_HOME/valid/configmap.yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: cm
|
||||||
|
data:
|
||||||
|
foo: bar
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat <<'EOF' >$DEMO_HOME/valid/validator.yaml
|
||||||
|
apiVersion: someteam.example.com/v1
|
||||||
|
kind: Validator
|
||||||
|
metadata:
|
||||||
|
name: notImportantHere
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat <<'EOF' >$DEMO_HOME/valid/kustomization.yaml
|
||||||
|
resources:
|
||||||
|
- configmap.yaml
|
||||||
|
|
||||||
|
validators:
|
||||||
|
- validator.yaml
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
The directory structure is as the following:
|
||||||
|
|
||||||
|
```
|
||||||
|
/tmp/tmp.69tTCuXuYc
|
||||||
|
├── kustomize
|
||||||
|
│ └── plugin
|
||||||
|
│ └── someteam.example.com
|
||||||
|
│ └── v1
|
||||||
|
│ └── validator
|
||||||
|
│ └── Validator
|
||||||
|
└── valid
|
||||||
|
├── configmap.yaml
|
||||||
|
├── kustomization.yaml
|
||||||
|
└── validator.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Define a helper function to run kustomize with the
|
||||||
|
correct environment and flags for plugins:
|
||||||
|
|
||||||
|
<!-- @defineKustomizeBd @validatorPlugin -->
|
||||||
|
```bash
|
||||||
|
function kustomizeBd {
|
||||||
|
XDG_CONFIG_HOME=$DEMO_HOME \
|
||||||
|
kustomize build \
|
||||||
|
--enable_alpha_plugins \
|
||||||
|
$DEMO_HOME/$1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Build the valid variant
|
||||||
|
|
||||||
|
<!-- @buildValid @validatorPlugin -->
|
||||||
|
```bash
|
||||||
|
kustomizeBd valid
|
||||||
|
```
|
||||||
|
The output contains a ConfigMap as
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
data:
|
||||||
|
foo: bar
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: cm
|
||||||
|
```
|
||||||
|
|
||||||
|
### Validator Failure
|
||||||
|
|
||||||
|
Now lets try a failed validator
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat <<'EOF' > $PLUGINDIR/Validator
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Non-zero indicates a failed validation
|
||||||
|
>&2 echo "Validation failed"
|
||||||
|
exit 1
|
||||||
|
|
||||||
|
EOF
|
||||||
|
chmod +x $PLUGINDIR/Validator
|
||||||
|
```
|
||||||
|
|
||||||
|
Build the valid variant
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kustomizeBd valid
|
||||||
|
```
|
||||||
|
The output contains the error information that is printed to stderr
|
||||||
|
by validator.
|
||||||
|
|
||||||
|
```
|
||||||
|
Validation failed
|
||||||
|
Error: failure in plugin configured via /tmp/kust-plugin-config-369137659; exit status 1: exit status 1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Input Modification
|
||||||
|
|
||||||
|
Typically a validator shouldn't modify the content to be validated. If it does, Kustomize will complain about it.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat <<'EOF' > $PLUGINDIR/Validator
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Modify the input content
|
||||||
|
|
||||||
|
sed 's/bar/baz/g'
|
||||||
|
|
||||||
|
EOF
|
||||||
|
chmod +x $PLUGINDIR/Validator
|
||||||
|
```
|
||||||
|
|
||||||
|
Then build
|
||||||
|
|
||||||
|
```
|
||||||
|
kustomizeBd valid
|
||||||
|
```
|
||||||
|
|
||||||
|
The error output will indicate you where is modified by the validator
|
||||||
|
|
||||||
|
```
|
||||||
|
Error: validator shouldn't modify the resource map: kunstruct not equal:
|
||||||
|
-- {"apiVersion":"v1","data":{"foo":"bar"},"kind":"ConfigMap","metadata":{"name":"cm"}}{nsfx:false,beh:unspecified},
|
||||||
|
-- {"apiVersion":"v1","data":{"foo":"baz"},"kind":"ConfigMap","metadata":{"name":"cm"}}{nsfx:false,beh:unspecified}
|
||||||
|
|
||||||
|
--
|
||||||
|
&resource.Resource{Kunstructured:(*kunstruct.UnstructAdapter)(0xc000118408), originalName:"cm", originalNs:"", options:(*types.GenArgs)(0xc00059e5e8), refBy:[]resid.ResId(nil), refVarNames:[]string(nil), namePrefixes:[]string{""}, nameSuffixes:[]string{""}}
|
||||||
|
------
|
||||||
|
&resource.Resource{Kunstructured:(*kunstruct.UnstructAdapter)(0xc000118510), originalName:"cm", originalNs:"", options:(*types.GenArgs)(0xc00059e5e8), refBy:[]resid.ResId(nil), refVarNames:[]string(nil), namePrefixes:[]string{""}, nameSuffixes:[]string{""}}
|
||||||
|
```
|
||||||
|
|
||||||
|
There is an exception that the validator can add a `validated-by` label to the **top** level resources.
|
||||||
|
|
||||||
|
<!-- @validatedByLabel @validatorPlugin -->
|
||||||
|
```bash
|
||||||
|
cat <<'EOF' > $PLUGINDIR/Validator
|
||||||
|
#!/usr/bin/bash
|
||||||
|
|
||||||
|
sed 's/^ name: cm$/ name: cm\n labels:\n validated-by: whatever/'
|
||||||
|
|
||||||
|
EOF
|
||||||
|
chmod +x $PLUGINDIR/Validator
|
||||||
|
```
|
||||||
|
|
||||||
|
Then build
|
||||||
|
|
||||||
|
<!-- @validatedByLabelBuild @validatorPlugin -->
|
||||||
|
```
|
||||||
|
kustomizeBd valid
|
||||||
|
```
|
||||||
|
|
||||||
|
The output will be
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
data:
|
||||||
|
foo: bar
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
validated-by: whatever
|
||||||
|
name: cm
|
||||||
|
```
|
||||||
|
|
||||||
|
## cleanup
|
||||||
|
|
||||||
|
<!-- @cleanup @validatorPlugin -->
|
||||||
|
```
|
||||||
|
rm -rf $DEMO_HOME
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user