Skip to content

Commit

Permalink
fix: [sc-106256] Add missing uri field to troubleshoot.sh types (#1578)
Browse files Browse the repository at this point in the history
* new no-uri flag for preflight
* implement load additional spec from URIs
  • Loading branch information
nvanthao authored Jul 18, 2024
1 parent 790c8d4 commit 04e656a
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 0 deletions.
1 change: 1 addition & 0 deletions cmd/preflight/cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ that a cluster meets the requirements to run an application.`,
// Dry run flag should be in cmd.PersistentFlags() flags made available to all subcommands
// Adding here to avoid that
cmd.Flags().Bool("dry-run", false, "print the preflight spec without running preflight checks")
cmd.Flags().Bool("no-uri", false, "When this flag is used, Preflight does not attempt to retrieve the spec referenced by the uri: field`")

k8sutil.AddFlags(cmd.Flags())

Expand Down
78 changes: 78 additions & 0 deletions internal/specs/specs.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,3 +361,81 @@ func LoadFromCluster(ctx context.Context, client kubernetes.Interface, selectors
RawSpecs: rawSpecs,
})
}

// LoadAdditionalSpecFromURIs loads additional specs from the URIs provided in the kinds.
// This function will modify kinds in place.
func LoadAdditionalSpecFromURIs(ctx context.Context, kinds *loader.TroubleshootKinds) {

obj := reflect.ValueOf(*kinds)

// iterate over all fields of the TroubleshootKinds
// e.g. SupportBundlesV1Beta2, PreflightsV1Beta2, etc.
for i := 0; i < obj.NumField(); i++ {
field := obj.Field(i)
if field.Kind() != reflect.Slice {
continue
}

// look at each spec in the slice
// e.g. each spec in []PreflightsV1Beta2
for count := 0; count < field.Len(); count++ {
currentSpec := field.Index(count)
specName := currentSpec.Type().Name()

// check if .Spec.Uri exists
specField := currentSpec.FieldByName("Spec")
if !specField.IsValid() {
continue
}
uriField := specField.FieldByName("Uri")
if uriField.Kind() != reflect.String {
continue
}

// download spec from URI
uri := uriField.String()
if uri == "" {
continue
}
rawSpec, err := downloadFromHttpURL(ctx, uri, nil)
if err != nil {
klog.Warningf("failed to download spec from URI %q: %v", uri, err)
continue
}

// load spec from raw spec
uriKinds, err := loader.LoadSpecs(ctx, loader.LoadOptions{RawSpec: string(rawSpec)})
if err != nil {
klog.Warningf("failed to load spec from URI %q: %v", uri, err)
continue
}

// replace original spec with the loaded spec from URI
newSpec := getFirstSpecOf(uriKinds, specName)
if !newSpec.IsValid() {
klog.Warningf("failed to read spec of type %s in URI %s", specName, uri)
continue
}
currentSpec.Set(newSpec)
}
}
}

// dynamically get spec from kinds of given name
// return first element of the spec slice
func getFirstSpecOf(kinds *loader.TroubleshootKinds, name string) reflect.Value {
obj := reflect.ValueOf(*kinds)
for i := 0; i < obj.NumField(); i++ {
field := obj.Field(i)
if field.Kind() != reflect.Slice {
continue
}
if field.Len() > 0 {
if field.Index(0).Type().Name() == name {
// return first element
return field.Index(0)
}
}
}
return reflect.Value{}
}
36 changes: 36 additions & 0 deletions internal/specs/specs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,3 +224,39 @@ spec:
require.NoError(t, err)
require.Len(t, specs.HostCollectorsV1Beta2, 1)
}

func TestLoadAdditionalSpecFromURIs(t *testing.T) {
m := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`apiVersion: troubleshoot.sh/v1beta2
apiVersion: troubleshoot.sh/v1beta2
kind: Preflight
metadata:
name: preflight-2
spec:
collectors:
- ceph: {}
`))
}))
defer m.Close()
kinds := loader.NewTroubleshootKinds()
kinds.PreflightsV1Beta2 = []troubleshootv1beta2.Preflight{
{
ObjectMeta: metav1.ObjectMeta{
Name: "preflight-1",
},
Spec: troubleshootv1beta2.PreflightSpec{
Uri: m.URL,
Collectors: []*troubleshootv1beta2.Collect{
{
DNS: &troubleshootv1beta2.DNS{},
},
},
},
},
}

LoadAdditionalSpecFromURIs(context.Background(), kinds)
require.Len(t, kinds.PreflightsV1Beta2, 1)
require.Len(t, kinds.PreflightsV1Beta2[0].Spec.Collectors, 1)
require.NotNil(t, kinds.PreflightsV1Beta2[0].Spec.Collectors[0].Ceph)
}
6 changes: 6 additions & 0 deletions pkg/preflight/read_specs.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ func readSpecs(args []string) (*loader.TroubleshootKinds, error) {
return nil, err
}

// Load additional specs from URIs
// only when no-uri flag is not set
if !viper.GetBool("no-uri") {
specs.LoadAdditionalSpecFromURIs(ctx, kinds)
}

ret := loader.NewTroubleshootKinds()

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

0 comments on commit 04e656a

Please sign in to comment.