Skip to content

Commit

Permalink
Merge pull request #164 from brendanjryan/bjr-output
Browse files Browse the repository at this point in the history
expose output formatter
  • Loading branch information
garethr authored Aug 10, 2019
2 parents 805845b + d7996f3 commit f21e689
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 19 deletions.
43 changes: 39 additions & 4 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,23 +87,57 @@ The file fixtures/test_crd.yaml containing a SealedSecret was not validated agai
Helm chart configurations generally have a reference to the source template in a comment
like so:

```
```console
# Source: chart/templates/frontend.yam
```

When kubeval detects these comments it will report the relevant chart template files in
the output.

```
```console
$ kubeval fixtures/multi_valid_source.yaml
The file chart/templates/primary.yaml contains a valid Service
The file chart/templates/primary.yaml contains a valid ReplicationControlle
```

## Configuring Output

## Full usage instructions
The output of `kubeval` can be configured using the `--output` flag (`-o`).

As of today `kubeval` supports the following output types:

- Plaintext `--output=stdout`
- JSON: `--output=json`

### Example Output

#### Plaintext

```console
$ kubeval my-invalid-rc.yaml
The document my-invalid-rc.yaml contains an invalid ReplicationController
--> spec.replicas: Invalid type. Expected: integer, given: string
```

#### JSON

```console
$ kubeval fixtures/invalid.yaml -o json
[
{
"filename": "fixtures/invalid.yaml",
"kind": "ReplicationController",
"status": "invalid",
"errors": [
"spec.replicas: Invalid type. Expected: [integer,null], given: string"
]
}
]
```

## Full usage instructions

```console
$ kubeval --help
Validate a Kubernetes YAML file against the relevant schema

Expand All @@ -119,7 +153,8 @@ Flags:
--ignore-missing-schemas Skip validation for resource definitions without a schema
-v, --kubernetes-version string Version of Kubernetes to validate against (default "master")
--openshift Use OpenShift schemas instead of upstream Kubernetes
--schema-location string Base URL used to download schemas. Can also be specified with the environment variable KUBEVAL_SCHEMA_LOCATION (default "https://kubernetesjsonschema.dev")
-o, --output string The format of the output of this script. Options are: [stdout json]
--schema-location string Base URL used to download schemas. Can also be specified with the environment variable KUBEVAL_SCHEMA_LOCATION
--skip-kinds strings Comma-separated list of case-sensitive kinds to skip when validating against schemas
--strict Disallow additional properties not in schema
--version version for kubeval
Expand Down
15 changes: 12 additions & 3 deletions kubeval/config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package kubeval

import "github.com/spf13/cobra"
import (
"fmt"

"github.com/spf13/cobra"
)

// DefaultSchemaLocation is the default location to search for schemas
const DefaultSchemaLocation = "https://kubernetesjsonschema.dev"
Expand Down Expand Up @@ -40,13 +44,16 @@ type Config struct {

// FileName is the name to be displayed when testing manifests read from stdin
FileName string
}

// OutputFormat is the name of the output formatter which will be used when
// reporting results to the user.
OutputFormat string
}

// NewDefaultConfig creates a Config with default values
func NewDefaultConfig() *Config {
return &Config{
FileName: "stdin",
FileName: "stdin",
KubernetesVersion: "master",
}
}
Expand All @@ -61,5 +68,7 @@ func AddKubevalFlags(cmd *cobra.Command, config *Config) *cobra.Command {
cmd.Flags().StringSliceVar(&config.KindsToSkip, "skip-kinds", []string{}, "Comma-separated list of case-sensitive kinds to skip when validating against schemas")
cmd.Flags().StringVar(&config.SchemaLocation, "schema-location", "", "Base URL used to download schemas. Can also be specified with the environment variable KUBEVAL_SCHEMA_LOCATION")
cmd.Flags().StringVarP(&config.KubernetesVersion, "kubernetes-version", "v", "master", "Version of Kubernetes to validate against")
cmd.Flags().StringVarP(&config.OutputFormat, "output", "o", "", fmt.Sprintf("The format of the output of this script. Options are: %v", validOutputs()))

return cmd
}
37 changes: 31 additions & 6 deletions kubeval/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,44 @@ import (
// TODO (brendanryan) move these structs to `/log` once we have removed the potential
// circular dependancy between this package and `/log`

// OutputManager controls how results of the `kubeval` evaluation will be recorded
// outputManager controls how results of the `kubeval` evaluation will be recorded
// and reported to the end user.
type OutputManager interface {
// This interface is kept private to ensure all implementations are closed within
// this package.
type outputManager interface {
Put(r ValidationResult) error
Flush() error
}

const (
outputSTD = "stdout"
outputJSON = "json"
)

func validOutputs() []string {
return []string{
outputSTD,
outputJSON,
}
}

func GetOutputManager(outFmt string) outputManager {
switch outFmt {
case outputSTD:
return newSTDOutputManager()
case outputJSON:
return newDefaultJSONOutputManager()
default:
return newSTDOutputManager()
}
}

// STDOutputManager reports `kubeval` results to stdout.
type STDOutputManager struct {
}

// NewSTDOutputManager instantiates a new instance of STDOutputManager.
func NewSTDOutputManager() *STDOutputManager {
// newSTDOutputManager instantiates a new instance of STDOutputManager.
func newSTDOutputManager() *STDOutputManager {
return &STDOutputManager{}
}

Expand Down Expand Up @@ -98,7 +123,7 @@ func getStatus(r ValidationResult) status {
return statusValid
}

func (j *jsonOutputManager) put(r ValidationResult) error {
func (j *jsonOutputManager) Put(r ValidationResult) error {
// stringify gojsonschema errors
// use a pre-allocated slice to ensure the json will have an
// empty array in the "zero" case
Expand All @@ -117,7 +142,7 @@ func (j *jsonOutputManager) put(r ValidationResult) error {
return nil
}

func (j *jsonOutputManager) flush() error {
func (j *jsonOutputManager) Flush() error {
b, err := json.Marshal(j.data)
if err != nil {
return err
Expand Down
16 changes: 10 additions & 6 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ var RootCmd = &cobra.Command{
log.Error(err)
os.Exit(1)
}
success, err = logResults(results, success)
success, err = logResults(config.OutputFormat, results, success)
if err != nil {
log.Error(err)
os.Exit(1)
Expand Down Expand Up @@ -105,7 +105,7 @@ var RootCmd = &cobra.Command{
success = false
continue
}
success, err = logResults(results, success)
success, err = logResults(config.OutputFormat, results, success)
if err != nil {
log.Error(err)
os.Exit(1)
Expand All @@ -119,10 +119,9 @@ var RootCmd = &cobra.Command{
},
}

func logResults(results []kubeval.ValidationResult, success bool) (bool, error) {
//// fetch output logger based on enviroments params -- for now we only support
//// the stdout logger
out := kubeval.NewSTDOutputManager()
func logResults(outFmt string, results []kubeval.ValidationResult, success bool) (bool, error) {
// fetch output logger based on enviroments params
out := kubeval.GetOutputManager(outFmt)

for _, result := range results {
if len(result.Errors) > 0 {
Expand All @@ -134,6 +133,11 @@ func logResults(results []kubeval.ValidationResult, success bool) (bool, error)
}
}

err := out.Flush()
if err != nil {
return false, err
}

return success, nil
}

Expand Down

0 comments on commit f21e689

Please sign in to comment.