@@ -3,13 +3,16 @@ package validation
33import (
44 "context"
55 "fmt"
6- "os"
7- "path/filepath"
8- "strings"
6+ "sync"
97
8+ "github.com/yannh/kubeconform/pkg/resource"
109 "github.com/yannh/kubeconform/pkg/validator"
1110)
1211
12+ const (
13+ numWorkers = 6
14+ )
15+
1316// KubeValidator is a struct that validates the kube configs associated with a cluster.
1417type KubeValidator struct {
1518 validatorObj validator.Validator
@@ -74,58 +77,88 @@ func (k *KubeValidator) RunSchemaValidation(
7477 ctx context.Context ,
7578 path string ,
7679) ([]ValidationResult , error ) {
77- results := []ValidationResult {}
78-
79- err := filepath .Walk (
80- path ,
81- func (subPath string , info os.FileInfo , err error ) error {
82- if err != nil {
83- return err
84- }
85-
86- if info .IsDir () || ! strings .HasSuffix (subPath , ".yaml" ) {
87- return nil
80+ kResults := []validator.Result {}
81+ resourcesChan , errChan := resource .FromFiles (ctx , []string {path }, nil )
82+ mut := sync.Mutex {}
83+ wg := sync.WaitGroup {}
84+
85+ // Based on implementation in
86+ // https://github.com/yannh/kubeconform/blob/master/cmd/kubeconform/main.go.
87+ for i := 0 ; i < numWorkers ; i ++ {
88+ wg .Add (1 )
89+ go func () {
90+ for res := range resourcesChan {
91+ mut .Lock ()
92+ kResults = append (kResults , k .validatorObj .ValidateResource (res ))
93+ mut .Unlock ()
8894 }
95+ wg .Done ()
96+ }()
97+ }
8998
90- file , err := os .Open (subPath )
91- if err != nil {
92- return err
99+ wg .Add (1 )
100+ go func () {
101+ // Process errors while discovering resources
102+ for err := range errChan {
103+ if err == nil {
104+ continue
93105 }
94106
95- for _ , kResult := range k .validatorObj .ValidateWithContext (ctx , subPath , file ) {
96- if kResult .Status == validator .Empty {
97- // Skip over empty results
98- continue
99- }
100-
101- result := ValidationResult {
102- Filename : kResult .Resource .Path ,
103- Status : kubeconformStatusToStatus (kResult .Status ),
104- }
107+ var kResult validator.Result
105108
106- if kResult .Err != nil {
107- result .Message = kResult .Err .Error ()
109+ if err , ok := err .(resource.DiscoveryError ); ok {
110+ kResult = validator.Result {
111+ Resource : resource.Resource {Path : err .Path },
112+ Err : err .Err ,
113+ Status : validator .Error ,
108114 }
109-
110- sig , err := kResult .Resource .Signature ()
111- if err == nil && sig != nil {
112- result .Kind = sig .Kind
113- result .Name = sig .Name
114- result .Namespace = sig .Namespace
115- result .Version = sig .Version
115+ } else {
116+ kResult = validator.Result {
117+ Resource : resource.Resource {},
118+ Err : err ,
119+ Status : validator .Error ,
116120 }
117-
118- results = append (results , result )
119121 }
122+ mut .Lock ()
123+ kResults = append (kResults , kResult )
124+ mut .Unlock ()
125+ }
126+ wg .Done ()
127+ }()
128+ wg .Wait ()
120129
121- return nil
122- },
123- )
130+ results := []ValidationResult {}
131+
132+ for _ , kResult := range kResults {
133+ if kResult .Status == validator .Empty {
134+ // Skip over empty results
135+ continue
136+ }
137+
138+ result := ValidationResult {
139+ Filename : kResult .Resource .Path ,
140+ Status : kStatusToStatus (kResult .Status ),
141+ }
142+
143+ if kResult .Err != nil {
144+ result .Message = kResult .Err .Error ()
145+ }
146+
147+ sig , err := kResult .Resource .Signature ()
148+ if err == nil && sig != nil {
149+ result .Kind = sig .Kind
150+ result .Name = sig .Name
151+ result .Namespace = sig .Namespace
152+ result .Version = sig .Version
153+ }
154+
155+ results = append (results , result )
156+ }
124157
125- return results , err
158+ return results , nil
126159}
127160
128- func kubeconformStatusToStatus (kStatus validator.Status ) Status {
161+ func kStatusToStatus (kStatus validator.Status ) Status {
129162 switch kStatus {
130163 case validator .Valid :
131164 return StatusValid
0 commit comments