Skip to content

Commit a66bb53

Browse files
authored
Merge pull request #154259 from kyle-a-wong/blathers/backport-release-25.4-153500
release-25.4: server: add txn bundle download; refactor handlers
2 parents a72af2c + f5bb643 commit a66bb53

File tree

9 files changed

+441
-93
lines changed

9 files changed

+441
-93
lines changed

pkg/server/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ go_library(
330330
"//pkg/util/log/logmetrics",
331331
"//pkg/util/log/logpb",
332332
"//pkg/util/log/severity",
333+
"//pkg/util/memzipper",
333334
"//pkg/util/metric",
334335
"//pkg/util/mon",
335336
"//pkg/util/netutil",
@@ -377,7 +378,6 @@ go_library(
377378
"@com_github_google_pprof//profile",
378379
"@com_github_gorilla_mux//:mux",
379380
"@com_github_grpc_ecosystem_grpc_gateway//runtime:go_default_library",
380-
"@com_github_grpc_ecosystem_grpc_gateway//utilities:go_default_library",
381381
"@com_github_lib_pq//:pq",
382382
"@com_github_marusama_semaphore//:semaphore",
383383
"@com_github_nightlyone_lockfile//:lockfile",

pkg/server/admin.go

Lines changed: 0 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,9 @@
66
package server
77

88
import (
9-
"bytes"
109
"context"
1110
"encoding/json"
1211
"fmt"
13-
"io"
14-
"net/http"
1512
"sort"
1613
"strconv"
1714
"strings"
@@ -77,10 +74,8 @@ import (
7774
"github.com/cockroachdb/errors"
7875
"github.com/cockroachdb/redact"
7976
gwruntime "github.com/grpc-ecosystem/grpc-gateway/runtime"
80-
gwutil "github.com/grpc-ecosystem/grpc-gateway/utilities"
8177
"google.golang.org/grpc"
8278
"google.golang.org/grpc/codes"
83-
"google.golang.org/grpc/metadata"
8479
grpcstatus "google.golang.org/grpc/status"
8580
"storj.io/drpc"
8681
"storj.io/drpc/drpcerr"
@@ -280,44 +275,6 @@ func (s *adminServer) RegisterDRPCService(d drpc.Mux) error {
280275
func (s *adminServer) RegisterGateway(
281276
ctx context.Context, mux *gwruntime.ServeMux, conn *grpc.ClientConn,
282277
) error {
283-
// Register the /_admin/v1/stmtbundle endpoint, which serves statement support
284-
// bundles as files.
285-
stmtBundlePattern := gwruntime.MustPattern(gwruntime.NewPattern(
286-
1, /* version */
287-
[]int{
288-
int(gwutil.OpLitPush), 0, int(gwutil.OpLitPush), 1, int(gwutil.OpLitPush), 2,
289-
int(gwutil.OpPush), 0, int(gwutil.OpConcatN), 1, int(gwutil.OpCapture), 3},
290-
[]string{"_admin", "v1", "stmtbundle", "id"},
291-
"", /* verb */
292-
))
293-
294-
mux.Handle("GET", stmtBundlePattern, func(
295-
w http.ResponseWriter, req *http.Request, pathParams map[string]string,
296-
) {
297-
idStr, ok := pathParams["id"]
298-
if !ok {
299-
http.Error(w, "missing id", http.StatusBadRequest)
300-
return
301-
}
302-
id, err := strconv.ParseInt(idStr, 10, 64)
303-
if err != nil {
304-
http.Error(w, "invalid id", http.StatusBadRequest)
305-
return
306-
}
307-
308-
// The privilege checks in the privilege checker below checks the user in the incoming
309-
// gRPC metadata.
310-
md := authserver.TranslateHTTPAuthInfoToGRPCMetadata(req.Context(), req)
311-
authCtx := metadata.NewIncomingContext(req.Context(), md)
312-
authCtx = s.AnnotateCtx(authCtx)
313-
if err := s.privilegeChecker.RequireViewActivityAndNoViewActivityRedactedPermission(authCtx); err != nil {
314-
http.Error(w, err.Error(), http.StatusForbidden)
315-
return
316-
}
317-
s.getStatementBundle(req.Context(), id, w)
318-
})
319-
320-
// Register the endpoints defined in the proto.
321278
return serverpb.RegisterAdminHandler(ctx, mux, conn)
322279
}
323280

@@ -2646,55 +2603,6 @@ func (s *adminServer) QueryPlan(
26462603
}, nil
26472604
}
26482605

2649-
// getStatementBundle retrieves the statement bundle with the given id and
2650-
// writes it out as an attachment. Note this function assumes the user has
2651-
// permission to access the statement bundle.
2652-
func (s *adminServer) getStatementBundle(ctx context.Context, id int64, w http.ResponseWriter) {
2653-
row, err := s.internalExecutor.QueryRowEx(
2654-
ctx, "admin-stmt-bundle", nil, /* txn */
2655-
sessiondata.NodeUserSessionDataOverride,
2656-
"SELECT bundle_chunks FROM system.statement_diagnostics WHERE id=$1 AND bundle_chunks IS NOT NULL",
2657-
id,
2658-
)
2659-
if err != nil {
2660-
http.Error(w, err.Error(), http.StatusInternalServerError)
2661-
return
2662-
}
2663-
if row == nil {
2664-
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
2665-
return
2666-
}
2667-
// Put together the entire bundle. Ideally we would stream it in chunks,
2668-
// but it's hard to return errors once we start.
2669-
var bundle bytes.Buffer
2670-
chunkIDs := row[0].(*tree.DArray).Array
2671-
for _, chunkID := range chunkIDs {
2672-
chunkRow, err := s.internalExecutor.QueryRowEx(
2673-
ctx, "admin-stmt-bundle", nil, /* txn */
2674-
sessiondata.NodeUserSessionDataOverride,
2675-
"SELECT data FROM system.statement_bundle_chunks WHERE id=$1",
2676-
chunkID,
2677-
)
2678-
if err != nil {
2679-
http.Error(w, err.Error(), http.StatusInternalServerError)
2680-
return
2681-
}
2682-
if chunkRow == nil {
2683-
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
2684-
return
2685-
}
2686-
data := chunkRow[0].(*tree.DBytes)
2687-
bundle.WriteString(string(*data))
2688-
}
2689-
2690-
w.Header().Set(
2691-
"Content-Disposition",
2692-
fmt.Sprintf("attachment; filename=stmt-bundle-%d.zip", id),
2693-
)
2694-
2695-
_, _ = io.Copy(w, &bundle)
2696-
}
2697-
26982606
// DecommissionPreCheck runs checks and returns the DecommissionPreCheckResponse
26992607
// for the given nodes.
27002608
func (s *systemAdminServer) DecommissionPreCheck(

pkg/server/apiconstants/constants.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,16 @@ const (
1717
// (This is also aliased via /health.)
1818
AdminHealth = AdminPrefix + "health"
1919

20+
// AdminStmtBundle is the URL at which we download statement bundles.
21+
// It does not share the admin handler because the implementation
22+
// downloads zip files, not gRPC responses.
23+
AdminStmtBundle = AdminPrefix + "stmtbundle/{id}"
24+
25+
// AdminTxnBundle is the URL at which we download transaction bundles.
26+
// It does not share the admin handler because the implementation
27+
// downloads zip files, not gRPC responses.
28+
AdminTxnBundle = AdminPrefix + "txnbundle/{id}"
29+
2030
// StatusPrefix is the root of the cluster statistics and metrics API.
2131
StatusPrefix = "/_status/"
2232

0 commit comments

Comments
 (0)