Skip to content

Commit

Permalink
feat: add yamlv3 validator
Browse files Browse the repository at this point in the history
  • Loading branch information
shreddedbacon committed Nov 6, 2023
1 parent 9fd5192 commit 20d6d9f
Show file tree
Hide file tree
Showing 5 changed files with 211 additions and 43 deletions.
31 changes: 31 additions & 0 deletions cmd/validate_compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,25 @@ var validateDockerCompose = &cobra.Command{
},
}

var validateDockerComposeWithErrors = &cobra.Command{
Use: "docker-compose-with-errors",
Aliases: []string{"dcwe"},
Short: "Verify docker-compose file for compatability with this tool with next versions of compose-go library",
Run: func(cmd *cobra.Command, args []string) {
dockerComposeFile, err := cmd.Flags().GetString("docker-compose")
if err != nil {
fmt.Println(fmt.Errorf("error reading docker-compose flag: %v", err))
os.Exit(1)
}

err = validateDockerComposeWithError(dockerComposeFile)
if err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
},
}

// ValidateDockerCompose validate a docker-compose file
func ValidateDockerCompose(file string, ignoreErrors, ignoreMisEnvFiles bool) error {
_, _, err := lagoon.UnmarshaDockerComposeYAML(file, ignoreErrors, ignoreMisEnvFiles, map[string]string{})
Expand All @@ -48,8 +67,20 @@ func ValidateDockerCompose(file string, ignoreErrors, ignoreMisEnvFiles bool) er
return nil
}

// validateDockerComposeWithErrors validate a docker-compose file yaml structure properly
func validateDockerComposeWithError(file string) error {
err := lagoon.ValidateUnmarshalDockerComposeYAML(file)
if err != nil {
return err
}
return nil
}

func init() {
validateCmd.AddCommand(validateDockerCompose)
validateCmd.AddCommand(validateDockerComposeWithErrors)
validateDockerCompose.Flags().StringP("docker-compose", "", "docker-compose.yml",
"The docker-compose.yml file to read.")
validateDockerComposeWithErrors.Flags().StringP("docker-compose", "", "docker-compose.yml",
"The docker-compose.yml file to read.")
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ require (
github.com/uselagoon/machinery v0.0.7
github.com/vshn/k8up v1.99.99
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.25.3
k8s.io/apimachinery v0.25.3
k8s.io/client-go v0.25.3
Expand Down Expand Up @@ -66,7 +67,6 @@ require (
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/klog/v2 v2.80.1 // indirect
k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect
k8s.io/utils v0.0.0-20221012122500-cfd413dd9e85 // indirect
Expand Down
15 changes: 15 additions & 0 deletions internal/lagoon/compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/compose-spec/compose-go/loader"
composetypes "github.com/compose-spec/compose-go/types"
goyaml "gopkg.in/yaml.v2"
goyamlv3 "gopkg.in/yaml.v3"
utilvalidation "k8s.io/apimachinery/pkg/util/validation"
)

Expand Down Expand Up @@ -69,6 +70,20 @@ func UnmarshalLagoonDockerComposeYAML(file string) ([]OriginalServiceOrder, erro
return l, nil
}

// use goyamlv3 that newer versions of compose-go uses to validate
func ValidateUnmarshalDockerComposeYAML(file string) error {
rawYAML, err := os.ReadFile(file)
if err != nil {
return fmt.Errorf("couldn't read %v: %v", file, err)
}
var m interface{}
err = goyamlv3.Unmarshal(rawYAML, &m)
if err != nil {
return err
}
return nil
}

// Checks the validity of the service name against the RFC1035 DNS label standard
func CheckServiceNameValidity(v goyaml.MapItem) error {
// go over the service map looking for the labels slice
Expand Down
100 changes: 100 additions & 0 deletions internal/lagoon/compose_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,3 +217,103 @@ func TestCheckLagoonLabel(t *testing.T) {
})
}
}

func TestUnmarshalLagoonDockerComposeYAML(t *testing.T) {
type args struct {
file string
}
tests := []struct {
name string
args args
wantErrMsg string
wantErr bool
}{
{
name: "test1 docker-compose drupal example",
args: args{
file: "../../test-resources/docker-compose/test1/docker-compose.yml",
},
wantErr: true,
wantErrMsg: `line 59: mapping key "<<" already defined at line 58`,
},
{
name: "test2 docker-compose node example",
args: args{
file: "../../test-resources/docker-compose/test2/docker-compose.yml",
},
},
{
name: "test3 docker-compose complex",
args: args{
file: "../../test-resources/docker-compose/test3/docker-compose.yml",
},
},
{
name: "test4 docker-compose complex",
args: args{
file: "../../test-resources/docker-compose/test4/docker-compose.yml",
},
},
{
name: "test5 docker-compose complex",
args: args{
file: "../../test-resources/docker-compose/test5/docker-compose.yml",
},
wantErr: true,
wantErrMsg: `line 57: mapping key "<<" already defined at line 56`,
},
{
name: "test6 docker-compose complex",
args: args{
file: "../../test-resources/docker-compose/test6/docker-compose.yml",
},
},
// these tests are specific to docker-compose validations, but will pass yaml validations
{
name: "test7 check an invalid docker-compose with ignoring non-string key errors (valid yaml)",
args: args{
file: "../../test-resources/docker-compose/test7/docker-compose.yml",
},
},
{
name: "test8 check an invalid docker-compose (same as test7 but not ignoring the errors)",
args: args{
file: "../../test-resources/docker-compose/test8/docker-compose.yml",
},
},
{
name: "test9 check an valid docker-compose with missing env_files",
args: args{
file: "../../test-resources/docker-compose/test9/docker-compose.yml",
},
},
{
name: "test10 check an valid docker-compose with missing env_files (same as test9 but not ignoring the errors)",
args: args{
file: "../../test-resources/docker-compose/test10/docker-compose.yml",
},
},
{
name: "test11 docker-compose service name with '.'",
args: args{
file: "../../test-resources/docker-compose/test11/docker-compose.yml",
},
},
// ^^ these tests are specific to docker-compose validations, but will pass yaml validations
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateUnmarshalDockerComposeYAML(tt.args.file)
if (err != nil) != tt.wantErr {
t.Errorf("ValidateUnmarshalDockerComposeYAML() error = %v, wantErr %v", err, tt.wantErr)
return
}
if err != nil {
if !strings.Contains(err.Error(), tt.wantErrMsg) {
t.Errorf("ValidateUnmarshalDockerComposeYAML() error = %v, wantErr %v", err.Error(), tt.wantErrMsg)
}
return
}
})
}
}
Loading

0 comments on commit 20d6d9f

Please sign in to comment.