mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-05-17 18:25:26 +00:00
update results field of ResourceList to implement function spec v1
This commit is contained in:
@@ -296,7 +296,7 @@ functionConfig:
|
||||
func ExampleBuild_validate() {
|
||||
fn := func(rl *framework.ResourceList) error {
|
||||
// validation results
|
||||
var validationResults []framework.ResultItem
|
||||
var validationResults framework.Results
|
||||
|
||||
// validate that each Deployment resource has spec.replicas set
|
||||
for i := range rl.Items {
|
||||
@@ -319,7 +319,7 @@ func ExampleBuild_validate() {
|
||||
if r != nil {
|
||||
continue
|
||||
}
|
||||
validationResults = append(validationResults, framework.ResultItem{
|
||||
validationResults = append(validationResults, &framework.Result{
|
||||
Severity: framework.Error,
|
||||
Message: "field is required",
|
||||
ResourceRef: yaml.ResourceIdentifier{
|
||||
@@ -327,20 +327,17 @@ func ExampleBuild_validate() {
|
||||
NameMeta: meta.ObjectMeta.NameMeta,
|
||||
},
|
||||
Field: framework.Field{
|
||||
Path: "spec.replicas",
|
||||
SuggestedValue: "1",
|
||||
Path: "spec.replicas",
|
||||
ProposedValue: "1",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if len(validationResults) > 0 {
|
||||
rl.Result = &framework.Result{
|
||||
Name: "replicas-validator",
|
||||
Items: validationResults,
|
||||
}
|
||||
rl.Results = validationResults
|
||||
}
|
||||
|
||||
return rl.Result
|
||||
return rl.Results
|
||||
}
|
||||
|
||||
cmd := command.Build(framework.ResourceListProcessorFunc(fn), command.StandaloneDisabled, true)
|
||||
@@ -370,15 +367,13 @@ items:
|
||||
// metadata:
|
||||
// name: foo
|
||||
// results:
|
||||
// name: replicas-validator
|
||||
// items:
|
||||
// - message: field is required
|
||||
// severity: error
|
||||
// resourceRef:
|
||||
// apiVersion: apps/v1
|
||||
// kind: Deployment
|
||||
// name: foo
|
||||
// field:
|
||||
// path: spec.replicas
|
||||
// suggestedValue: "1"
|
||||
// - message: field is required
|
||||
// severity: error
|
||||
// resourceRef:
|
||||
// apiVersion: apps/v1
|
||||
// kind: Deployment
|
||||
// name: foo
|
||||
// field:
|
||||
// path: spec.replicas
|
||||
// proposedValue: "1"
|
||||
}
|
||||
|
||||
@@ -17,6 +17,22 @@ import (
|
||||
// This framework facilitates building functions that receive and emit ResourceLists,
|
||||
// as required by the specification.
|
||||
type ResourceList struct {
|
||||
// Items is the ResourceList.items input and output value.
|
||||
//
|
||||
// e.g. given the function input:
|
||||
//
|
||||
// kind: ResourceList
|
||||
// items:
|
||||
// - kind: Deployment
|
||||
// ...
|
||||
// - kind: Service
|
||||
// ...
|
||||
//
|
||||
// Items will be a slice containing the Deployment and Service resources
|
||||
// Mutating functions will alter this field during processing.
|
||||
// This field is required.
|
||||
Items []*yaml.RNode `yaml:"items" json:"items"`
|
||||
|
||||
// FunctionConfig is the ResourceList.functionConfig input value.
|
||||
//
|
||||
// e.g. given the input:
|
||||
@@ -33,25 +49,10 @@ type ResourceList struct {
|
||||
// foo: var
|
||||
FunctionConfig *yaml.RNode `yaml:"functionConfig" json:"functionConfig"`
|
||||
|
||||
// Items is the ResourceList.items input and output value.
|
||||
//
|
||||
// e.g. given the function input:
|
||||
//
|
||||
// kind: ResourceList
|
||||
// items:
|
||||
// - kind: Deployment
|
||||
// ...
|
||||
// - kind: Service
|
||||
// ...
|
||||
//
|
||||
// Items will be a slice containing the Deployment and Service resources
|
||||
// Mutating functions will alter this field during processing.
|
||||
Items []*yaml.RNode `yaml:"items" json:"items"`
|
||||
|
||||
// Result is ResourceList.result output value.
|
||||
// Results is ResourceList.results output value.
|
||||
// Validating functions can optionally use this field to communicate structured
|
||||
// validation error data to downstream functions.
|
||||
Result *Result `yaml:"results" json:"results"`
|
||||
Results Results `yaml:"results" json:"results"`
|
||||
}
|
||||
|
||||
// ResourceListProcessor is implemented by configuration functions built with this framework
|
||||
@@ -119,8 +120,8 @@ func Execute(p ResourceListProcessor, rlSource *kio.ByteReadWriter) error {
|
||||
|
||||
// Write the results
|
||||
// Set the ResourceList.results for validating functions
|
||||
if rl.Result != nil && len(rl.Result.Items) > 0 {
|
||||
b, err := yaml.Marshal(rl.Result)
|
||||
if len(rl.Results) > 0 {
|
||||
b, err := yaml.Marshal(rl.Results)
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
|
||||
@@ -16,33 +16,31 @@ import (
|
||||
|
||||
func TestExecute_Result(t *testing.T) {
|
||||
p := framework.ResourceListProcessorFunc(func(rl *framework.ResourceList) error {
|
||||
err := &framework.Result{
|
||||
Name: "Incompatible config",
|
||||
Items: []framework.ResultItem{
|
||||
{
|
||||
Message: "bad value for replicas",
|
||||
Severity: framework.Error,
|
||||
ResourceRef: yaml.ResourceIdentifier{
|
||||
TypeMeta: yaml.TypeMeta{APIVersion: "v1", Kind: "Deployment"},
|
||||
NameMeta: yaml.NameMeta{Name: "tester", Namespace: "default"},
|
||||
},
|
||||
Field: framework.Field{
|
||||
Path: ".spec.Replicas",
|
||||
CurrentValue: "0",
|
||||
SuggestedValue: "3",
|
||||
},
|
||||
File: framework.File{
|
||||
Path: "/path/to/deployment.yaml",
|
||||
Index: 0,
|
||||
},
|
||||
err := &framework.Results{
|
||||
{
|
||||
Message: "bad value for replicas",
|
||||
Severity: framework.Error,
|
||||
ResourceRef: yaml.ResourceIdentifier{
|
||||
TypeMeta: yaml.TypeMeta{APIVersion: "v1", Kind: "Deployment"},
|
||||
NameMeta: yaml.NameMeta{Name: "tester", Namespace: "default"},
|
||||
},
|
||||
{
|
||||
Message: "some error",
|
||||
Severity: framework.Error,
|
||||
Field: framework.Field{
|
||||
Path: ".spec.Replicas",
|
||||
CurrentValue: "0",
|
||||
ProposedValue: "3",
|
||||
},
|
||||
File: framework.File{
|
||||
Path: "/path/to/deployment.yaml",
|
||||
Index: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
Message: "some error",
|
||||
Severity: framework.Error,
|
||||
Tags: map[string]string{"foo": "bar"},
|
||||
},
|
||||
}
|
||||
rl.Result = err
|
||||
rl.Results = *err
|
||||
return err
|
||||
})
|
||||
out := new(bytes.Buffer)
|
||||
@@ -62,7 +60,7 @@ items:
|
||||
assert.EqualError(t, err, `[error] v1/Deployment/default/tester .spec.Replicas: bad value for replicas
|
||||
|
||||
[error] : some error`)
|
||||
assert.Equal(t, 1, err.(*framework.Result).ExitCode())
|
||||
assert.Equal(t, 1, err.(*framework.Results).ExitCode())
|
||||
assert.Equal(t, `apiVersion: config.kubernetes.io/v1
|
||||
kind: ResourceList
|
||||
items:
|
||||
@@ -74,21 +72,21 @@ items:
|
||||
spec:
|
||||
replicas: 0
|
||||
results:
|
||||
name: Incompatible config
|
||||
items:
|
||||
- message: bad value for replicas
|
||||
severity: error
|
||||
resourceRef:
|
||||
apiVersion: v1
|
||||
kind: Deployment
|
||||
name: tester
|
||||
namespace: default
|
||||
field:
|
||||
path: .spec.Replicas
|
||||
currentValue: "0"
|
||||
suggestedValue: "3"
|
||||
file:
|
||||
path: /path/to/deployment.yaml
|
||||
- message: some error
|
||||
severity: error`, strings.TrimSpace(out.String()))
|
||||
- message: bad value for replicas
|
||||
severity: error
|
||||
resourceRef:
|
||||
apiVersion: v1
|
||||
kind: Deployment
|
||||
name: tester
|
||||
namespace: default
|
||||
field:
|
||||
path: .spec.Replicas
|
||||
currentValue: "0"
|
||||
proposedValue: "3"
|
||||
file:
|
||||
path: /path/to/deployment.yaml
|
||||
- message: some error
|
||||
severity: error
|
||||
tags:
|
||||
foo: bar`, strings.TrimSpace(out.String()))
|
||||
}
|
||||
|
||||
@@ -23,25 +23,30 @@ const (
|
||||
)
|
||||
|
||||
// ResultItem defines a validation result
|
||||
type ResultItem struct {
|
||||
// Message is a human readable message
|
||||
Message string `yaml:"message,omitempty"`
|
||||
type Result struct {
|
||||
// Message is a human readable message. This field is required.
|
||||
Message string `yaml:"message,omitempty" json:"message,omitempty"`
|
||||
|
||||
// Severity is the severity of this result
|
||||
Severity Severity `yaml:"severity,omitempty"`
|
||||
Severity Severity `yaml:"severity,omitempty" json:"severity,omitempty"`
|
||||
|
||||
// ResourceRef is a reference to a resource
|
||||
ResourceRef yaml.ResourceIdentifier `yaml:"resourceRef,omitempty"`
|
||||
// ResourceRef is a reference to a resource.
|
||||
// Required fields: apiVersion, kind, name.
|
||||
ResourceRef yaml.ResourceIdentifier `yaml:"resourceRef,omitempty" json:"resourceRef,omitempty"`
|
||||
|
||||
// Field is a reference to the field in a resource this result refers to
|
||||
Field Field `yaml:"field,omitempty"`
|
||||
Field Field `yaml:"field,omitempty" json:"field,omitempty"`
|
||||
|
||||
// File references a file containing the resource this result refers to
|
||||
File File `yaml:"file,omitempty"`
|
||||
File File `yaml:"file,omitempty" json:"file,omitempty"`
|
||||
|
||||
// Tags is an unstructured key value map stored with a result that may be set
|
||||
// by external tools to store and retrieve arbitrary metadata
|
||||
Tags map[string]string `yaml:"tags,omitempty" json:"tags,omitempty"`
|
||||
}
|
||||
|
||||
// String provides a human-readable message for the result item
|
||||
func (i ResultItem) String() string {
|
||||
func (i Result) String() string {
|
||||
identifier := i.ResourceRef
|
||||
var idStringList []string
|
||||
if identifier.APIVersion != "" {
|
||||
@@ -65,47 +70,41 @@ func (i ResultItem) String() string {
|
||||
|
||||
// File references a file containing a resource
|
||||
type File struct {
|
||||
// Path is relative path to the file containing the resource
|
||||
Path string `yaml:"path,omitempty"`
|
||||
// Path is relative path to the file containing the resource.
|
||||
// This field is required.
|
||||
Path string `yaml:"path,omitempty" json:"path,omitempty"`
|
||||
|
||||
// Index is the index into the file containing the resource
|
||||
// (i.e. if there are multiple resources in a single file)
|
||||
Index int `yaml:"index,omitempty"`
|
||||
Index int `yaml:"index,omitempty" json:"index,omitempty"`
|
||||
}
|
||||
|
||||
// Field references a field in a resource
|
||||
type Field struct {
|
||||
// Path is the field path
|
||||
Path string `yaml:"path,omitempty"`
|
||||
// Path is the field path. This field is required.
|
||||
Path string `yaml:"path,omitempty" json:"path,omitempty"`
|
||||
|
||||
// CurrentValue is the current field value
|
||||
CurrentValue string `yaml:"currentValue,omitempty"`
|
||||
CurrentValue interface{} `yaml:"currentValue,omitempty" json:"currentValue,omitempty"`
|
||||
|
||||
// SuggestedValue is the suggested field value
|
||||
SuggestedValue string `yaml:"suggestedValue,omitempty"`
|
||||
// ProposedValue is the proposed value of the field to fix an issue.
|
||||
ProposedValue interface{} `yaml:"proposedValue,omitempty" json:"proposedValue,omitempty"`
|
||||
}
|
||||
|
||||
// Result defines a function result which will be set on the emitted ResourceList
|
||||
type Result struct {
|
||||
// Name is the name of the function creating the result
|
||||
Name string `yaml:"name,omitempty"`
|
||||
type Results []*Result
|
||||
|
||||
// Items are the individual results
|
||||
Items []ResultItem `yaml:"items,omitempty"`
|
||||
}
|
||||
|
||||
// Error enables a Result to be returned as an error
|
||||
func (e Result) Error() string {
|
||||
// Error enables Results to be returned as an error
|
||||
func (e Results) Error() string {
|
||||
var msgs []string
|
||||
for _, i := range e.Items {
|
||||
for _, i := range e {
|
||||
msgs = append(msgs, i.String())
|
||||
}
|
||||
return strings.Join(msgs, "\n\n")
|
||||
}
|
||||
|
||||
// ExitCode provides the exit code based on the result's severity
|
||||
func (e Result) ExitCode() int {
|
||||
for _, i := range e.Items {
|
||||
func (e Results) ExitCode() int {
|
||||
for _, i := range e {
|
||||
if i.Severity == Error {
|
||||
return 1
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user