Skip to content

Commit

Permalink
Gracefully handle unreachable URIs in loadSupportBundleSpecsFromURIs (#…
Browse files Browse the repository at this point in the history
…1383)

* gracefully handle unreachable URIs in loadSupportBundleSpecsFromURIs

* let caller decide how to handle the error

* fix klog import

* Add a test to ensure failing to load uri does not error

---------

Co-authored-by: Evans Mungai <evans@replicated.com>
  • Loading branch information
diamonwiggins and banjoh authored Oct 27, 2023
1 parent 1d2c119 commit 08c3fcf
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 15 deletions.
15 changes: 12 additions & 3 deletions cmd/troubleshoot/cli/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,21 +232,29 @@ the %s Admin Console to begin analysis.`
return nil
}

// loadSupportBundleSpecsFromURIs loads support bundle specs from URIs
func loadSupportBundleSpecsFromURIs(ctx context.Context, kinds *loader.TroubleshootKinds) (*loader.TroubleshootKinds, error) {
remoteRawSpecs := []string{}
for _, s := range kinds.SupportBundlesV1Beta2 {
if s.Spec.Uri != "" && util.IsURL(s.Spec.Uri) {
// We are using LoadSupportBundleSpec function here since it handles prompting
// users to accept insecure connections
// There is an opportunity to refactor this code in favour of the Loader APIs
// TODO: Pass ctx to LoadSupportBundleSpec
rawSpec, err := supportbundle.LoadSupportBundleSpec(s.Spec.Uri)
if err != nil {
return nil, errors.Wrapf(err, "failed to load support bundle from URI %q", s.Spec.Uri)
// In the event a spec can't be loaded, we'll just skip it and print a warning
klog.Warningf("unable to load support bundle from URI: %q: %v", s.Spec.Uri, err)
continue
}
remoteRawSpecs = append(remoteRawSpecs, string(rawSpec))
}
}

if len(remoteRawSpecs) == 0 {
return kinds, nil
}

return loader.LoadSpecs(ctx, loader.LoadOptions{
RawSpecs: remoteRawSpecs,
})
Expand All @@ -264,9 +272,10 @@ func loadSpecs(ctx context.Context, args []string, client kubernetes.Interface)
if !viper.GetBool("no-uri") {
moreKinds, err := loadSupportBundleSpecsFromURIs(ctx, kinds)
if err != nil {
return nil, nil, err
klog.Warningf("unable to load support bundles from URIs: %v", err)
} else {
kinds.Add(moreKinds)
}
kinds.Add(moreKinds)
}

// Check if we have any collectors to run in the troubleshoot specs
Expand Down
56 changes: 44 additions & 12 deletions cmd/troubleshoot/cli/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,29 @@ import (
"context"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"

"github.com/replicatedhq/troubleshoot/pkg/httputil"
"github.com/replicatedhq/troubleshoot/pkg/loader"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

var orig = `
apiVersion: troubleshoot.sh/v1beta2
kind: SupportBundle
metadata:
name: sb-1
spec:
uri: $MY_URI
collectors:
- configMap:
name: kube-root-ca.crt
namespace: default
`

func Test_loadSupportBundleSpecsFromURIs(t *testing.T) {
// Run a webserver to serve the spec
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
Expand All @@ -25,18 +41,7 @@ spec:
}))
defer srv.Close()

orig := `
apiVersion: troubleshoot.sh/v1beta2
kind: SupportBundle
metadata:
name: sb-1
spec:
uri: ` + srv.URL + `
collectors:
- configMap:
name: kube-root-ca.crt
namespace: default
`
orig := strings.ReplaceAll(orig, "$MY_URI", srv.URL)

ctx := context.Background()
kinds, err := loader.LoadSpecs(ctx, loader.LoadOptions{RawSpec: orig})
Expand All @@ -49,3 +54,30 @@ spec:
require.Len(t, moreKinds.SupportBundlesV1Beta2, 1)
assert.NotNil(t, moreKinds.SupportBundlesV1Beta2[0].Spec.Collectors[0].ClusterInfo)
}

func Test_loadSupportBundleSpecsFromURIs_TimeoutError(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
time.Sleep(2 * time.Second) // this will cause a timeout
}))
defer srv.Close()
ctx := context.Background()

kinds, err := loader.LoadSpecs(ctx, loader.LoadOptions{
RawSpec: strings.ReplaceAll(orig, "$MY_URI", srv.URL),
})
require.NoError(t, err)

// Set the timeout on the http client to 10ms
// supportbundle.LoadSupportBundleSpec does not yet use the context
before := httputil.GetHttpClient().Timeout
httputil.GetHttpClient().Timeout = 10 * time.Millisecond
defer func() {
// Reinstate the original timeout. Its a global var so we need to reset it
httputil.GetHttpClient().Timeout = before
}()

kindsAfter, err := loadSupportBundleSpecsFromURIs(ctx, kinds)
require.NoError(t, err)

assert.Equal(t, kinds, kindsAfter)
}

0 comments on commit 08c3fcf

Please sign in to comment.