mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-11 17:12:51 +00:00
Enable functions to defer failures
so multiple validators can be run sequentially without shortcircuiting the pipeline
This commit is contained in:
@@ -151,6 +151,10 @@ type ContainerFilter struct {
|
||||
|
||||
Results *yaml.RNode
|
||||
|
||||
DeferFailure bool
|
||||
|
||||
Exit error
|
||||
|
||||
// SetFlowStyleForConfig sets the style for config to Flow when serializing it
|
||||
SetFlowStyleForConfig bool
|
||||
|
||||
@@ -160,7 +164,18 @@ type ContainerFilter struct {
|
||||
checkInput func(string)
|
||||
}
|
||||
|
||||
func (c ContainerFilter) GetExit() error {
|
||||
return c.Exit
|
||||
}
|
||||
|
||||
type DeferFailureFunction interface {
|
||||
GetExit() error
|
||||
}
|
||||
|
||||
func (c ContainerFilter) String() string {
|
||||
if c.DeferFailure {
|
||||
return fmt.Sprintf("%s deferFailure: %v", c.Image, c.DeferFailure)
|
||||
}
|
||||
return c.Image
|
||||
}
|
||||
|
||||
@@ -300,18 +315,9 @@ func (c *ContainerFilter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
}
|
||||
cmd.Stdin = in
|
||||
cmd.Stdout = out
|
||||
if err := cmd.Run(); err != nil {
|
||||
// write the results file on failure
|
||||
results, e := r.Read()
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
if e = c.doResults(r); e != nil {
|
||||
return nil, e
|
||||
}
|
||||
// return the results from the function even on failure
|
||||
return results, err
|
||||
}
|
||||
|
||||
// don't exit immediately if the function fails -- write out the validation
|
||||
c.Exit = cmd.Run()
|
||||
|
||||
output, err := r.Read()
|
||||
if err != nil {
|
||||
@@ -322,6 +328,10 @@ func (c *ContainerFilter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if c.Exit != nil && !c.DeferFailure {
|
||||
return append(output, saved...), c.Exit
|
||||
}
|
||||
|
||||
// annotate any generated Resources with a path and index if they don't already have one
|
||||
if err := kioutil.DefaultPathAnnotation(functionDir, output); err != nil {
|
||||
return nil, err
|
||||
@@ -380,6 +390,7 @@ func (c *ContainerFilter) getArgs() []string {
|
||||
|
||||
// tell functions to write error messages to stderr as well as results
|
||||
os.Setenv("LOG_TO_STDERR", "true")
|
||||
os.Setenv("STRUCTURED_RESULTS", "true")
|
||||
|
||||
// export the local environment vars to the container
|
||||
for _, pair := range os.Environ() {
|
||||
|
||||
@@ -18,13 +18,14 @@ import (
|
||||
|
||||
func TestContainerFilter_Filter(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
input []string
|
||||
expectedOutput []string
|
||||
expectedError string
|
||||
expectedResults string
|
||||
noMakeResultsFile bool
|
||||
instance ContainerFilter
|
||||
name string
|
||||
input []string
|
||||
expectedOutput []string
|
||||
expectedError string
|
||||
expectedSavedError string
|
||||
expectedResults string
|
||||
noMakeResultsFile bool
|
||||
instance ContainerFilter
|
||||
}{
|
||||
{
|
||||
name: "add_path_annotation",
|
||||
@@ -220,6 +221,87 @@ metadata:
|
||||
`,
|
||||
},
|
||||
|
||||
{
|
||||
name: "write_results_defer_failure",
|
||||
expectedSavedError: "exit status 1",
|
||||
instance: ContainerFilter{
|
||||
DeferFailure: true,
|
||||
args: []string{"sh", "-c",
|
||||
`echo '
|
||||
apiVersion: config.kubernetes.io/v1alpha1
|
||||
kind: ResourceList
|
||||
items:
|
||||
- apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: deployment-foo
|
||||
- apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: service-foo
|
||||
results:
|
||||
- apiVersion: config.k8s.io/v1alpha1
|
||||
kind: ObjectError
|
||||
name: "some-validator"
|
||||
items:
|
||||
- type: error
|
||||
message: "some message"
|
||||
resourceRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: foo
|
||||
namespace: bar
|
||||
file:
|
||||
path: deploy.yaml
|
||||
index: 0
|
||||
field:
|
||||
path: "spec.template.spec.containers[3].resources.limits.cpu"
|
||||
currentValue: "200"
|
||||
suggestedValue: "2"
|
||||
' && cat not-real-dir
|
||||
`,
|
||||
},
|
||||
},
|
||||
expectedOutput: []string{
|
||||
`
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: deployment-foo
|
||||
annotations:
|
||||
config.kubernetes.io/path: 'deployment_deployment-foo.yaml'
|
||||
`,
|
||||
`
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: service-foo
|
||||
annotations:
|
||||
config.kubernetes.io/path: 'service_service-foo.yaml'
|
||||
`,
|
||||
},
|
||||
expectedResults: `
|
||||
- apiVersion: config.k8s.io/v1alpha1
|
||||
kind: ObjectError
|
||||
name: "some-validator"
|
||||
items:
|
||||
- type: error
|
||||
message: "some message"
|
||||
resourceRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: foo
|
||||
namespace: bar
|
||||
file:
|
||||
path: deploy.yaml
|
||||
index: 0
|
||||
field:
|
||||
path: "spec.template.spec.containers[3].resources.limits.cpu"
|
||||
currentValue: "200"
|
||||
suggestedValue: "2"
|
||||
`,
|
||||
},
|
||||
|
||||
{
|
||||
name: "write_results_non_0_exit_missing_file",
|
||||
expectedError: "open /not/real/file: no such file or directory",
|
||||
@@ -332,6 +414,13 @@ metadata:
|
||||
return
|
||||
}
|
||||
|
||||
if tt.expectedSavedError != "" {
|
||||
if !assert.EqualError(t, tt.instance.Exit, tt.expectedSavedError) {
|
||||
t.FailNow()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ type FunctionSpec struct {
|
||||
// Network is the name of the network to use from a container
|
||||
Network string `json:"network,omitempty" yaml:"network,omitempty"`
|
||||
|
||||
DeferFailure bool `json:"deferFailure,omitempty" yaml:"deferFailure,omitempty"`
|
||||
|
||||
// Container is the spec for running a function as a container
|
||||
Container ContainerSpec `json:"container,omitempty" yaml:"container,omitempty"`
|
||||
|
||||
|
||||
Reference in New Issue
Block a user