Skip to content

Commit

Permalink
Pod details from support bundle (#2277)
Browse files Browse the repository at this point in the history
* get failed pod details from support bundle

Co-authored-by: Grayson Null <graysonnull@me.com>
  • Loading branch information
sgalsaleh and GraysonNull committed Oct 28, 2021
1 parent 81ce092 commit 0540bfe
Show file tree
Hide file tree
Showing 15 changed files with 377 additions and 108 deletions.
6 changes: 1 addition & 5 deletions go.mod
Expand Up @@ -24,7 +24,6 @@ require (
github.com/dexidp/dex v0.0.0-20210802203454-3fac2ab6bc3b
github.com/docker/distribution v2.7.1+incompatible
github.com/docker/go-units v0.4.0
github.com/dsnet/compress v0.0.1 // indirect
github.com/fatih/color v1.12.0
github.com/frankban/quicktest v1.13.0 // indirect
github.com/garyburd/redigo v1.6.0 // indirect
Expand All @@ -51,20 +50,18 @@ require (
github.com/mattn/go-sqlite3 v1.14.8
github.com/mholt/archiver v3.1.1+incompatible
github.com/mitchellh/hashstructure v1.1.0
github.com/nwaples/rardecode v1.0.0 // indirect
github.com/open-policy-agent/opa v0.24.0
github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6
github.com/openshift/api v0.0.0-20210513192832-efee9960e6fd // indirect
github.com/openshift/client-go v0.0.0-20210503124028-ac0910aac9fa
github.com/otiai10/copy v1.0.2
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2
github.com/pierrec/lz4 v2.2.6+incompatible // indirect
github.com/pkg/errors v0.9.1
github.com/pmezard/go-difflib v1.0.0
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
github.com/rancher/wrangler v0.8.3
github.com/replicatedhq/kurl v0.0.0-20210414162418-8d6211901244
github.com/replicatedhq/troubleshoot v0.18.0
github.com/replicatedhq/troubleshoot v0.19.0
github.com/replicatedhq/yaml/v3 v3.0.0-beta5-replicatedhq
github.com/robfig/cron v1.2.0
github.com/robfig/cron/v3 v3.0.1
Expand All @@ -77,7 +74,6 @@ require (
github.com/stretchr/testify v1.7.0
github.com/tj/go-spin v1.1.0
github.com/vmware-tanzu/velero v1.5.4
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
github.com/yvasiyarov/go-metrics v0.0.0-20150112132944-c25f46c4b940 // indirect
github.com/yvasiyarov/gorelic v0.0.7 // indirect
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20160601141957-9c099fbc30e9 // indirect; indirect=
Expand Down
15 changes: 8 additions & 7 deletions go.sum
Expand Up @@ -820,8 +820,9 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4=
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk=
github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0=
Expand Down Expand Up @@ -1416,8 +1417,8 @@ github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJE
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
github.com/nwaples/rardecode v1.0.0 h1:r7vGuS5akxOnR4JQSkko62RJ1ReCMXxQRPtxsiFMBOs=
github.com/nwaples/rardecode v1.0.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
github.com/nwaples/rardecode v1.1.2 h1:Cj0yZY6T1Zx1R7AhTbyGSALm44/Mmq+BAPc4B/p/d3M=
github.com/nwaples/rardecode v1.1.2/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
Expand Down Expand Up @@ -1543,8 +1544,8 @@ github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoU
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/lz4 v2.2.6+incompatible h1:6aCX4/YZ9v8q69hTyiR7dNLnTA3fgtKHVVW5BCd5Znw=
github.com/pierrec/lz4 v2.2.6+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM=
github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.0.0-20181023235946-059132a15dd0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
Expand Down Expand Up @@ -1631,8 +1632,8 @@ github.com/replicatedhq/kurl v0.0.0-20210414162418-8d6211901244 h1:aSORttMXeqRXg
github.com/replicatedhq/kurl v0.0.0-20210414162418-8d6211901244/go.mod h1:SoROyLOtkt95R1COPVzdCi5FZbMmATPHohQQzW9V9ds=
github.com/replicatedhq/termui/v3 v3.1.1-0.20200811145416-f40076d26851/go.mod h1:JDxG6+uubnk9/BZ2yUsyAJJwlptjrnmB2MPF5d2Xe/8=
github.com/replicatedhq/troubleshoot v0.10.18/go.mod h1:8oFRnMJlFjzJ490eq72iLEN7DGJjkgLx22Z1vX6WwU0=
github.com/replicatedhq/troubleshoot v0.18.0 h1:Gug+67PrIk6BLkjsT4AW+U6S/oMuqL/C0OMz1tzbu5Q=
github.com/replicatedhq/troubleshoot v0.18.0/go.mod h1:RbTswOcNaUURaDWdUYvKj8SmuJEh+dYWlaEalgC4tUU=
github.com/replicatedhq/troubleshoot v0.19.0 h1:9aIIr1Nnqf7UAyNjjkq3/YbQJKgK4sJbxZEjJ8xnNzc=
github.com/replicatedhq/troubleshoot v0.19.0/go.mod h1:aWhykK6xiTpfbLMjPpqnonih34avLwEag52Y9CYzb/Y=
github.com/replicatedhq/yaml/v3 v3.0.0-beta5-replicatedhq h1:PwPggruelq2336c1Ayg5STFqgbn/QB1tWLQwrVlU7ZQ=
github.com/replicatedhq/yaml/v3 v3.0.0-beta5-replicatedhq/go.mod h1:Txa7LopbYCU8aRgmNe0n+y/EPMz50NbCPcVVJBquwag=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
Expand Down
2 changes: 2 additions & 0 deletions pkg/handlers/handlers.go
Expand Up @@ -57,6 +57,8 @@ func RegisterSessionAuthRoutes(r *mux.Router, kotsStore store.Store, handler KOT
HandlerFunc(middleware.EnforceAccess(policy.AppSupportbundleWrite, handler.CollectSupportBundle))
r.Name("ShareSupportBundle").Path("/api/v1/troubleshoot/app/{appSlug}/supportbundle/{bundleId}/share").Methods("POST").
HandlerFunc(middleware.EnforceAccess(policy.AppSupportbundleWrite, handler.ShareSupportBundle))
r.Name("GetPodDetailsFromSupportBundle").Path("/api/v1/troubleshoot/app/{appSlug}/supportbundle/{bundleId}/pod").Methods("GET").
HandlerFunc(middleware.EnforceAccess(policy.AppSupportbundleRead, handler.GetPodDetailsFromSupportBundle))

// redactor routes
r.Name("UpdateRedact").Path("/api/v1/redact/set").Methods("PUT").
Expand Down
11 changes: 11 additions & 0 deletions pkg/handlers/handlers_test.go
Expand Up @@ -165,6 +165,17 @@ var HandlerPolicyTests = map[string][]HandlerPolicyTest{
ExpectStatus: http.StatusOK,
},
},
"GetPodDetailsFromSupportBundle": {
{
Vars: map[string]string{"appSlug": "my-app", "bundleId": "234"},
Roles: []rbactypes.Role{rbac.ClusterAdminRole},
SessionRoles: []string{rbac.ClusterAdminRoleID},
Calls: func(storeRecorder *mock_store.MockStoreMockRecorder, handlerRecorder *mock_handlers.MockKOTSHandlerMockRecorder) {
handlerRecorder.GetPodDetailsFromSupportBundle(gomock.Any(), gomock.Any())
},
ExpectStatus: http.StatusOK,
},
},

// redactor routes
"UpdateRedact": {
Expand Down
1 change: 1 addition & 0 deletions pkg/handlers/interface.go
Expand Up @@ -19,6 +19,7 @@ type KOTSHandler interface {
DownloadSupportBundle(w http.ResponseWriter, r *http.Request) // TODO: appSlug
CollectSupportBundle(w http.ResponseWriter, r *http.Request)
ShareSupportBundle(w http.ResponseWriter, r *http.Request)
GetPodDetailsFromSupportBundle(w http.ResponseWriter, r *http.Request)

// redactor routes
UpdateRedact(w http.ResponseWriter, r *http.Request)
Expand Down
12 changes: 12 additions & 0 deletions pkg/handlers/mock/mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

61 changes: 58 additions & 3 deletions pkg/handlers/troubleshoot.go
Expand Up @@ -18,6 +18,8 @@ import (
"github.com/replicatedhq/kots/pkg/supportbundle/types"
"github.com/replicatedhq/kots/pkg/util"
redact2 "github.com/replicatedhq/troubleshoot/pkg/redact"
tsupportbundle "github.com/replicatedhq/troubleshoot/pkg/supportbundle"
tsupportbundletypes "github.com/replicatedhq/troubleshoot/pkg/supportbundle/types"
)

type GetSupportBundleResponse struct {
Expand Down Expand Up @@ -81,6 +83,19 @@ type GetSupportBundleRedactionsResponse struct {
Error string `json:"error,omitempty"`
}

type GetPodDetailsFromSupportBundleResponse struct {
tsupportbundletypes.PodDetails `json:",inline"`

Success bool `json:"success"`
Error string `json:"error,omitempty"`
}

type PodContainer struct {
Name string `json:"name"`
LogsFilePath string `json:"logsFilePath"`
IsInitContainer bool `json:"isInitContainer"`
}

type PutSupportBundleRedactions struct {
Redactions redact2.RedactionList `json:"redactions"`
}
Expand Down Expand Up @@ -128,11 +143,20 @@ func (h *Handler) GetSupportBundleFiles(w http.ResponseWriter, r *http.Request)
bundleID := mux.Vars(r)["bundleId"]
filenames := r.URL.Query()["filename"]

files, err := supportbundle.GetFilesContents(bundleID, filenames)
bundleArchive, err := store.GetStore().GetSupportBundleArchive(bundleID)
if err != nil {
logger.Error(err)
logger.Error(errors.Wrap(err, "failed to get support bundle archive"))
getSupportBundleFilesResponse.Error = "failed to get support bundle archive"
JSON(w, http.StatusInternalServerError, nil)
return
}
defer os.RemoveAll(bundleArchive)

files, err := tsupportbundle.GetFilesContents(bundleArchive, filenames)
if err != nil {
logger.Error(errors.Wrap(err, "failed to get files"))
getSupportBundleFilesResponse.Error = "failed to get files"
JSON(w, 500, getSupportBundleFilesResponse)
JSON(w, http.StatusInternalServerError, getSupportBundleFilesResponse)
return
}

Expand Down Expand Up @@ -482,6 +506,37 @@ func (h *Handler) GetSupportBundleRedactions(w http.ResponseWriter, r *http.Requ
JSON(w, http.StatusOK, getSupportBundleRedactionsResponse)
}

func (h *Handler) GetPodDetailsFromSupportBundle(w http.ResponseWriter, r *http.Request) {
getPodDetailsFromSupportBundleResponse := GetPodDetailsFromSupportBundleResponse{
Success: false,
}

bundleID := mux.Vars(r)["bundleId"]
podName := r.URL.Query().Get("podName")
podNamespace := r.URL.Query().Get("podNamespace")

bundleArchive, err := store.GetStore().GetSupportBundleArchive(bundleID)
if err != nil {
logger.Error(errors.Wrap(err, "failed to get support bundle archive"))
JSON(w, http.StatusInternalServerError, nil)
return
}
defer os.RemoveAll(bundleArchive)

podDetails, err := tsupportbundle.GetPodDetails(bundleArchive, podNamespace, podName)
if err != nil {
logger.Error(errors.Wrap(err, "failed to get pod details"))
getPodDetailsFromSupportBundleResponse.Error = "failed to get pod details"
JSON(w, http.StatusInternalServerError, getPodDetailsFromSupportBundleResponse)
return
}

getPodDetailsFromSupportBundleResponse.PodDetails = *podDetails
getPodDetailsFromSupportBundleResponse.Success = true

JSON(w, http.StatusOK, getPodDetailsFromSupportBundleResponse)
}

// SetSupportBundleRedactions route is UNAUTHENTICATED
// This request comes from the `kubectl support-bundle` command.
func (h *Handler) SetSupportBundleRedactions(w http.ResponseWriter, r *http.Request) {
Expand Down
10 changes: 6 additions & 4 deletions pkg/store/kotsstore/supportbundle_store.go
Expand Up @@ -587,10 +587,11 @@ func insightsFromResults(results []byte) ([]types.SupportBundleInsight, error) {
DesiredPosition string `json:"desiredPosition"`
}
type DBInsight struct {
Name string `json:"name"`
Severity string `json:"severity"`
Insight Insight `json:"insight"`
Labels Labels `json:"labels"`
Name string `json:"name"`
Severity string `json:"severity"`
Insight Insight `json:"insight"`
Labels Labels `json:"labels"`
InvolvedObject *corev1.ObjectReference `json:"involvedObject,omitempty"`
}

dbInsights := []DBInsight{}
Expand All @@ -610,6 +611,7 @@ func insightsFromResults(results []byte) ([]types.SupportBundleInsight, error) {
Icon: dbInsight.Labels.IconUri,
IconKey: dbInsight.Labels.IconKey,
DesiredPosition: desiredPosition,
InvolvedObject: dbInsight.InvolvedObject,
}
insights = append(insights, insight)
}
Expand Down
80 changes: 0 additions & 80 deletions pkg/supportbundle/supportbundle.go
Expand Up @@ -85,86 +85,6 @@ func CreateBundle(requestedID string, appID string, archivePath string) (*types.
return store.GetStore().CreateSupportBundle(id, appID, archivePath, marshalledTree)
}

// GetFilesContents will return the file contents for filenames matching the filenames
// parameter.
func GetFilesContents(bundleID string, filenames []string) (map[string][]byte, error) {
bundleArchive, err := store.GetStore().GetSupportBundleArchive(bundleID)
if err != nil {
return nil, errors.Wrap(err, "failed to get bundle")
}
defer os.RemoveAll(bundleArchive)

bundleDir, err := ioutil.TempDir("", "kots")
if err != nil {
return nil, errors.Wrap(err, "failed to create tmp dir")
}
defer os.RemoveAll(bundleDir)

tarGz := archiver.TarGz{
Tar: &archiver.Tar{
ImplicitTopLevelFolder: false,
},
}
if err := tarGz.Unarchive(bundleArchive, bundleDir); err != nil {
return nil, errors.Wrap(err, "failed to unarchive")
}

files := map[string][]byte{}
err = filepath.Walk(bundleDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}

if len(path) <= len(bundleDir) {
return nil
}

if info.IsDir() {
return nil
}

// the following tries to find the actual file path of the desired files in the support bundle
// this is needed to handle old and new support bundle formats
// where old support bundles don't include a top level subdirectory and the new ones do
// this basically compares file paths after trimming the subdirectory path from both (if exists)
// for example: "support-bundle-2021-09-10T18_50_35/support-bundle-2021-09-10T18_50_35/path/to/file"
relPath, err := filepath.Rel(bundleDir, path) // becomes: "support-bundle-2021-09-10T18_50_35/path/to/file"
if err != nil {
return errors.Wrap(err, "failed to get relative path")
}

trimmedRelPath := SupportBundleNameRegex.ReplaceAllString(relPath, "") // becomes: "path/to/file"
trimmedRelPath = strings.TrimPrefix(trimmedRelPath, string(os.PathSeparator)) // extra measure to ensure no leading slashes. for example: "/path/to/file"
if trimmedRelPath == "" {
return nil
}

for _, filename := range filenames {
trimmedFileName := SupportBundleNameRegex.ReplaceAllString(filename, "")
trimmedFileName = strings.TrimPrefix(trimmedFileName, string(os.PathSeparator))
if trimmedFileName == "" {
continue
}
if trimmedRelPath == trimmedFileName {
content, err := ioutil.ReadFile(path)
if err != nil {
return errors.Wrap(err, "failed to read file")
}

files[filename] = content
return nil
}
}

return nil
})
if err != nil {
return nil, errors.Wrap(err, "failed to walk")
}

return files, nil
}

func GetSpecSecretName(appSlug string) string {
return fmt.Sprintf("kotsadm-%s-supportbundle", appSlug)
}
Expand Down
17 changes: 10 additions & 7 deletions pkg/supportbundle/types/types.go
Expand Up @@ -2,6 +2,8 @@ package types

import (
"time"

corev1 "k8s.io/api/core/v1"
)

type ByCreated []*SupportBundle
Expand Down Expand Up @@ -49,13 +51,14 @@ type SupportBundleAnalysis struct {
}

type SupportBundleInsight struct {
Key string `json:"key"`
Severity string `json:"severity"`
Primary string `json:"primary"`
Detail string `json:"detail"`
Icon string `json:"icon"`
IconKey string `json:"iconKey"`
DesiredPosition float64 `json:"desiredPosition"`
Key string `json:"key"`
Severity string `json:"severity"`
Primary string `json:"primary"`
Detail string `json:"detail"`
Icon string `json:"icon"`
IconKey string `json:"iconKey"`
DesiredPosition float64 `json:"desiredPosition"`
InvolvedObject *corev1.ObjectReference `json:"involvedObject"`
}

type FileTree struct {
Expand Down

0 comments on commit 0540bfe

Please sign in to comment.