@@ -2,7 +2,6 @@ package loader
22
33import (
44 "context"
5- "strings"
65
76 "github.com/pkg/errors"
87 "github.com/replicatedhq/troubleshoot/internal/util"
@@ -35,20 +34,34 @@ type parsedDoc struct {
3534type LoadOptions struct {
3635 RawSpecs []string
3736 RawSpec string
37+
38+ // If true, the loader will return an error if any of the specs are not valid
39+ // else the invalid specs will be ignored
40+ Strict bool
3841}
3942
4043// LoadSpecs takes sources to load specs from and returns a TroubleshootKinds object
4144// that contains all the parsed troubleshoot specs.
4245//
43- // The fetched specs need to be yaml documents. The documents can be a multidoc yaml
44- // separated by "---" which get split and parsed one at a time. This function will
45- // return an error if any of the documents are not valid yaml. If Secrets or ConfigMaps
46- // are found, they will be parsed and the support bundle, redactor or preflight spec
47- // will be extracted from them, else they will be ignored.
48- // Any other yaml documents will be ignored.
46+ // The fetched specs should be yaml documents. The documents can be multidoc yamls
47+ // separated by "---" which get split and parsed one at a time. All troubleshoot
48+ // specs are extracted from the documents and returned in a TroubleshootKinds object.
49+ //
50+ // If Secrets or ConfigMaps are found, they are parsed and the support bundle, redactor
51+ // or preflight spec extracted from them. All other yaml documents will be ignored.
52+ //
53+ // If the `Strict` flag is set to true, this function will return an error if any of
54+ // the documents are not valid, else the invalid documents will be ignored.
4955func LoadSpecs (ctx context.Context , opt LoadOptions ) (* TroubleshootKinds , error ) {
5056 opt .RawSpecs = append (opt .RawSpecs , opt .RawSpec )
51- return loadFromStrings (opt .RawSpecs ... )
57+ l := specLoader {
58+ strict : opt .Strict ,
59+ }
60+ return l .loadFromStrings (opt .RawSpecs ... )
61+ }
62+
63+ type specLoader struct {
64+ strict bool
5265}
5366
5467type TroubleshootKinds struct {
@@ -78,13 +91,13 @@ func NewTroubleshootKinds() *TroubleshootKinds {
7891}
7992
8093// loadFromStrings accepts a list of strings (exploded) which should be yaml documents
81- func loadFromStrings (rawSpecs ... string ) (* TroubleshootKinds , error ) {
94+ func ( l * specLoader ) loadFromStrings (rawSpecs ... string ) (* TroubleshootKinds , error ) {
8295 splitdocs := []string {}
8396 multiRawDocs := []string {}
8497
8598 // 1. First split multidoc yaml documents.
8699 for _ , rawSpec := range rawSpecs {
87- multiRawDocs = append (multiRawDocs , strings . Split (rawSpec , " \n --- \n " )... )
100+ multiRawDocs = append (multiRawDocs , util . SplitYAML (rawSpec )... )
88101 }
89102
90103 // 2. Go through each document to see if it is a configmap, secret or troubleshoot kind
@@ -95,13 +108,19 @@ func loadFromStrings(rawSpecs ...string) (*TroubleshootKinds, error) {
95108
96109 err := yaml .Unmarshal ([]byte (rawDoc ), & parsed )
97110 if err != nil {
111+ if ! l .strict {
112+ continue
113+ }
98114 return nil , types .NewExitCodeError (constants .EXIT_CODE_SPEC_ISSUES , errors .Wrapf (err , "failed to parse yaml: '%s'" , string (rawDoc )))
99115 }
100116
101117 if isConfigMap (parsed ) || isSecret (parsed ) {
102118 // Extract specs from configmap or secret
103119 obj , _ , err := decoder .Decode ([]byte (rawDoc ), nil , nil )
104120 if err != nil {
121+ if ! l .strict {
122+ continue
123+ }
105124 return nil , types .NewExitCodeError (constants .EXIT_CODE_SPEC_ISSUES ,
106125 errors .Wrapf (err , "failed to decode raw spec: '%s'" , string (rawDoc )),
107126 )
@@ -110,13 +129,13 @@ func loadFromStrings(rawSpecs ...string) (*TroubleshootKinds, error) {
110129 // 3. Extract the raw troubleshoot specs
111130 switch v := obj .(type ) {
112131 case * v1.ConfigMap :
113- specs , err := getSpecFromConfigMap (v )
132+ specs , err := l . getSpecFromConfigMap (v )
114133 if err != nil {
115134 return nil , types .NewExitCodeError (constants .EXIT_CODE_SPEC_ISSUES , err )
116135 }
117136 splitdocs = append (splitdocs , specs ... )
118137 case * v1.Secret :
119- specs , err := getSpecFromSecret (v )
138+ specs , err := l . getSpecFromSecret (v )
120139 if err != nil {
121140 return nil , types .NewExitCodeError (constants .EXIT_CODE_SPEC_ISSUES , err )
122141 }
@@ -133,21 +152,31 @@ func loadFromStrings(rawSpecs ...string) (*TroubleshootKinds, error) {
133152 }
134153
135154 // 4. Then load the specs into the kinds struct
136- return loadFromSplitDocs (splitdocs )
155+ return l . loadFromSplitDocs (splitdocs )
137156}
138157
139- func loadFromSplitDocs (splitdocs []string ) (* TroubleshootKinds , error ) {
158+ func ( l * specLoader ) loadFromSplitDocs (splitdocs []string ) (* TroubleshootKinds , error ) {
140159 kinds := NewTroubleshootKinds ()
141160
142161 for _ , doc := range splitdocs {
143162 converted , err := docrewrite .ConvertToV1Beta2 ([]byte (doc ))
144163 if err != nil {
145- return nil , types .NewExitCodeError (constants .EXIT_CODE_SPEC_ISSUES , errors .Wrapf (err , "failed to convert doc to troubleshoot.sh/v1beta2 kind: '%s'" , doc ))
164+ if ! l .strict {
165+ continue
166+ }
167+ return nil , types .NewExitCodeError (constants .EXIT_CODE_SPEC_ISSUES ,
168+ errors .Wrapf (err , "failed to convert doc to troubleshoot.sh/v1beta2 kind: '\n %s'" , doc ),
169+ )
146170 }
147171
148172 obj , _ , err := decoder .Decode ([]byte (converted ), nil , nil )
149173 if err != nil {
150- return nil , types .NewExitCodeError (constants .EXIT_CODE_SPEC_ISSUES , errors .Wrapf (err , "failed to decode '%s'" , converted ))
174+ if ! l .strict {
175+ continue
176+ }
177+ return nil , types .NewExitCodeError (constants .EXIT_CODE_SPEC_ISSUES ,
178+ errors .Wrapf (err , "failed to decode '%s'" , converted ),
179+ )
151180 }
152181
153182 switch spec := obj .(type ) {
@@ -193,98 +222,52 @@ func isConfigMap(parsedDocHead parsedDoc) bool {
193222}
194223
195224// getSpecFromConfigMap extracts multiple troubleshoot specs from a secret
196- func getSpecFromConfigMap (cm * v1.ConfigMap ) ([]string , error ) {
225+ func ( l * specLoader ) getSpecFromConfigMap (cm * v1.ConfigMap ) ([]string , error ) {
197226 specs := []string {}
198227
199228 str , ok := cm .Data [constants .SupportBundleKey ]
200229 if ok {
201- spec , err := validateYaml (str )
202- if err != nil {
203- return nil , err
204- }
205- specs = append (specs , util .SplitYAML (spec )... )
230+ specs = append (specs , util .SplitYAML (str )... )
206231 }
207232 str , ok = cm .Data [constants .RedactorKey ]
208233 if ok {
209- spec , err := validateYaml (str )
210- if err != nil {
211- return nil , err
212- }
213- specs = append (specs , util .SplitYAML (spec )... )
234+ specs = append (specs , util .SplitYAML (str )... )
214235 }
215236 str , ok = cm .Data [constants .PreflightKey ]
216237 if ok {
217- spec , err := validateYaml (str )
218- if err != nil {
219- return nil , err
220- }
221- specs = append (specs , util .SplitYAML (spec )... )
238+ specs = append (specs , util .SplitYAML (str )... )
222239 }
223240
224241 return specs , nil
225242}
226243
227244// getSpecFromSecret extracts multiple troubleshoot specs from a secret
228- func getSpecFromSecret (secret * v1.Secret ) ([]string , error ) {
245+ func ( l * specLoader ) getSpecFromSecret (secret * v1.Secret ) ([]string , error ) {
229246 specs := []string {}
230247
231248 specBytes , ok := secret .Data [constants .SupportBundleKey ]
232249 if ok {
233- spec , err := validateYaml (string (specBytes ))
234- if err != nil {
235- return nil , err
236- }
237- specs = append (specs , util .SplitYAML (spec )... )
250+ specs = append (specs , util .SplitYAML (string (specBytes ))... )
238251 }
239252 specBytes , ok = secret .Data [constants .RedactorKey ]
240253 if ok {
241- spec , err := validateYaml (string (specBytes ))
242- if err != nil {
243- return nil , err
244- }
245- specs = append (specs , util .SplitYAML (spec )... )
254+ specs = append (specs , util .SplitYAML (string (specBytes ))... )
246255 }
247256 specBytes , ok = secret .Data [constants .PreflightKey ]
248257 if ok {
249- spec , err := validateYaml (string (specBytes ))
250- if err != nil {
251- return nil , err
252- }
253- specs = append (specs , util .SplitYAML (spec )... )
258+ specs = append (specs , util .SplitYAML (string (specBytes ))... )
254259 }
255260 str , ok := secret .StringData [constants .SupportBundleKey ]
256261 if ok {
257- spec , err := validateYaml (str )
258- if err != nil {
259- return nil , err
260- }
261- specs = append (specs , util .SplitYAML (spec )... )
262+ specs = append (specs , util .SplitYAML (str )... )
262263 }
263264 str , ok = secret .StringData [constants .RedactorKey ]
264265 if ok {
265- spec , err := validateYaml (str )
266- if err != nil {
267- return nil , err
268- }
269- specs = append (specs , util .SplitYAML (spec )... )
266+ specs = append (specs , util .SplitYAML (str )... )
270267 }
271268 str , ok = secret .StringData [constants .PreflightKey ]
272269 if ok {
273- spec , err := validateYaml (str )
274- if err != nil {
275- return nil , err
276- }
277- specs = append (specs , util .SplitYAML (spec )... )
270+ specs = append (specs , util .SplitYAML (str )... )
278271 }
279272 return specs , nil
280273}
281-
282- func validateYaml (raw string ) (string , error ) {
283- var parsed map [string ]any
284- err := yaml .Unmarshal ([]byte (raw ), & parsed )
285- if err != nil {
286- return "" , errors .Wrapf (err , "failed to parse yaml: '%s'" , string (raw ))
287- }
288-
289- return raw , nil
290- }
0 commit comments