Skip to content

Commit

Permalink
update results field of ResourceList to implement function spec v1
Browse files Browse the repository at this point in the history
  • Loading branch information
natasha41575 committed Oct 19, 2021
1 parent 5765ab4 commit 9a4e941
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 96 deletions.
31 changes: 13 additions & 18 deletions kyaml/fn/framework/command/example_test.go
Expand Up @@ -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 {
Expand All @@ -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{
Expand All @@ -334,13 +334,10 @@ func ExampleBuild_validate() {
}

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)
Expand Down Expand Up @@ -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
// suggestedValue: "1"
}
36 changes: 18 additions & 18 deletions kyaml/fn/framework/framework.go
Expand Up @@ -17,6 +17,21 @@ 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.
Items []*yaml.RNode `yaml:"items" json:"items"`

// FunctionConfig is the ResourceList.functionConfig input value.
//
// e.g. given the input:
Expand All @@ -33,25 +48,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.
// 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
Expand Down Expand Up @@ -119,8 +119,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)
}
Expand Down
84 changes: 41 additions & 43 deletions kyaml/fn/framework/framework_test.go
Expand Up @@ -16,39 +16,37 @@ 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",
SuggestedValue: "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)
source := &kio.ByteReadWriter{Reader: bytes.NewBufferString(`
kind: ResourceList
apiVersion: config.kubernetes.io/v1alpha1
apiVersion: config.kubernetes.io/v1
items:
- kind: Deployment
apiVersion: v1
Expand All @@ -62,8 +60,8 @@ 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, `apiVersion: config.kubernetes.io/v1alpha1
assert.Equal(t, 1, err.(*framework.Results).ExitCode())
assert.Equal(t, `apiVersion: config.kubernetes.io/v1
kind: ResourceList
items:
- kind: Deployment
Expand All @@ -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"
suggestedValue: "3"
file:
path: /path/to/deployment.yaml
- message: some error
severity: error
tags:
foo: bar`, strings.TrimSpace(out.String()))
}
31 changes: 14 additions & 17 deletions kyaml/fn/framework/result.go
Expand Up @@ -23,7 +23,7 @@ const (
)

// ResultItem defines a validation result
type ResultItem struct {
type Result struct {
// Message is a human readable message
Message string `yaml:"message,omitempty"`

Expand All @@ -38,10 +38,14 @@ type ResultItem struct {

// File references a file containing the resource this result refers to
File File `yaml:"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"`
}

// 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 != "" {
Expand Down Expand Up @@ -79,33 +83,26 @@ type Field struct {
Path string `yaml:"path,omitempty"`

// CurrentValue is the current field value
CurrentValue string `yaml:"currentValue,omitempty"`
CurrentValue interface{} `yaml:"currentValue,omitempty"`

// SuggestedValue is the suggested field value
SuggestedValue string `yaml:"suggestedValue,omitempty"`
SuggestedValue interface{} `yaml:"suggestedValue,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"`

// Items are the individual results
Items []ResultItem `yaml:"items,omitempty"`
}
type Results []*Result

// 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
}
Expand Down

0 comments on commit 9a4e941

Please sign in to comment.