Skip to content

Commit 04e656a

Browse files
authored
fix: [sc-106256] Add missing uri field to troubleshoot.sh types (#1578)
* new no-uri flag for preflight * implement load additional spec from URIs
1 parent 790c8d4 commit 04e656a

File tree

4 files changed

+121
-0
lines changed

4 files changed

+121
-0
lines changed

cmd/preflight/cli/root.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ that a cluster meets the requirements to run an application.`,
7171
// Dry run flag should be in cmd.PersistentFlags() flags made available to all subcommands
7272
// Adding here to avoid that
7373
cmd.Flags().Bool("dry-run", false, "print the preflight spec without running preflight checks")
74+
cmd.Flags().Bool("no-uri", false, "When this flag is used, Preflight does not attempt to retrieve the spec referenced by the uri: field`")
7475

7576
k8sutil.AddFlags(cmd.Flags())
7677

internal/specs/specs.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,3 +361,81 @@ func LoadFromCluster(ctx context.Context, client kubernetes.Interface, selectors
361361
RawSpecs: rawSpecs,
362362
})
363363
}
364+
365+
// LoadAdditionalSpecFromURIs loads additional specs from the URIs provided in the kinds.
366+
// This function will modify kinds in place.
367+
func LoadAdditionalSpecFromURIs(ctx context.Context, kinds *loader.TroubleshootKinds) {
368+
369+
obj := reflect.ValueOf(*kinds)
370+
371+
// iterate over all fields of the TroubleshootKinds
372+
// e.g. SupportBundlesV1Beta2, PreflightsV1Beta2, etc.
373+
for i := 0; i < obj.NumField(); i++ {
374+
field := obj.Field(i)
375+
if field.Kind() != reflect.Slice {
376+
continue
377+
}
378+
379+
// look at each spec in the slice
380+
// e.g. each spec in []PreflightsV1Beta2
381+
for count := 0; count < field.Len(); count++ {
382+
currentSpec := field.Index(count)
383+
specName := currentSpec.Type().Name()
384+
385+
// check if .Spec.Uri exists
386+
specField := currentSpec.FieldByName("Spec")
387+
if !specField.IsValid() {
388+
continue
389+
}
390+
uriField := specField.FieldByName("Uri")
391+
if uriField.Kind() != reflect.String {
392+
continue
393+
}
394+
395+
// download spec from URI
396+
uri := uriField.String()
397+
if uri == "" {
398+
continue
399+
}
400+
rawSpec, err := downloadFromHttpURL(ctx, uri, nil)
401+
if err != nil {
402+
klog.Warningf("failed to download spec from URI %q: %v", uri, err)
403+
continue
404+
}
405+
406+
// load spec from raw spec
407+
uriKinds, err := loader.LoadSpecs(ctx, loader.LoadOptions{RawSpec: string(rawSpec)})
408+
if err != nil {
409+
klog.Warningf("failed to load spec from URI %q: %v", uri, err)
410+
continue
411+
}
412+
413+
// replace original spec with the loaded spec from URI
414+
newSpec := getFirstSpecOf(uriKinds, specName)
415+
if !newSpec.IsValid() {
416+
klog.Warningf("failed to read spec of type %s in URI %s", specName, uri)
417+
continue
418+
}
419+
currentSpec.Set(newSpec)
420+
}
421+
}
422+
}
423+
424+
// dynamically get spec from kinds of given name
425+
// return first element of the spec slice
426+
func getFirstSpecOf(kinds *loader.TroubleshootKinds, name string) reflect.Value {
427+
obj := reflect.ValueOf(*kinds)
428+
for i := 0; i < obj.NumField(); i++ {
429+
field := obj.Field(i)
430+
if field.Kind() != reflect.Slice {
431+
continue
432+
}
433+
if field.Len() > 0 {
434+
if field.Index(0).Type().Name() == name {
435+
// return first element
436+
return field.Index(0)
437+
}
438+
}
439+
}
440+
return reflect.Value{}
441+
}

internal/specs/specs_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,3 +224,39 @@ spec:
224224
require.NoError(t, err)
225225
require.Len(t, specs.HostCollectorsV1Beta2, 1)
226226
}
227+
228+
func TestLoadAdditionalSpecFromURIs(t *testing.T) {
229+
m := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
230+
w.Write([]byte(`apiVersion: troubleshoot.sh/v1beta2
231+
apiVersion: troubleshoot.sh/v1beta2
232+
kind: Preflight
233+
metadata:
234+
name: preflight-2
235+
spec:
236+
collectors:
237+
- ceph: {}
238+
`))
239+
}))
240+
defer m.Close()
241+
kinds := loader.NewTroubleshootKinds()
242+
kinds.PreflightsV1Beta2 = []troubleshootv1beta2.Preflight{
243+
{
244+
ObjectMeta: metav1.ObjectMeta{
245+
Name: "preflight-1",
246+
},
247+
Spec: troubleshootv1beta2.PreflightSpec{
248+
Uri: m.URL,
249+
Collectors: []*troubleshootv1beta2.Collect{
250+
{
251+
DNS: &troubleshootv1beta2.DNS{},
252+
},
253+
},
254+
},
255+
},
256+
}
257+
258+
LoadAdditionalSpecFromURIs(context.Background(), kinds)
259+
require.Len(t, kinds.PreflightsV1Beta2, 1)
260+
require.Len(t, kinds.PreflightsV1Beta2[0].Spec.Collectors, 1)
261+
require.NotNil(t, kinds.PreflightsV1Beta2[0].Spec.Collectors[0].Ceph)
262+
}

pkg/preflight/read_specs.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ func readSpecs(args []string) (*loader.TroubleshootKinds, error) {
2929
return nil, err
3030
}
3131

32+
// Load additional specs from URIs
33+
// only when no-uri flag is not set
34+
if !viper.GetBool("no-uri") {
35+
specs.LoadAdditionalSpecFromURIs(ctx, kinds)
36+
}
37+
3238
ret := loader.NewTroubleshootKinds()
3339

3440
// Concatenate all preflight inclusterSpecs that don't have an upload destination

0 commit comments

Comments
 (0)