Skip to main content

add-admin-v2-endpoint

Use when adding or modifying a Redpanda admin v2 ConnectRPC endpoint — authoring the protobuf under proto/redpanda/core/admin/v2/, wiring it into the Bazel build, implementing the C++ service handler under src/v/redpanda/admin/services/, registering it on the admin server, and regenerating Python bindings for ducktape integration tests. Covers both new RPCs on an existing service and brand-new services.

Quellinformationen

Repository
redpanda-data/redpanda
Letzte Quellaktivität
11. Mai 2026 um 18:23
Erkannte Sprache von SKILL.md
Englisch
Sterne
12.641
Forks
798

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
add-admin-v2-endpoint
description
Use when adding or modifying a Redpanda admin v2 ConnectRPC endpoint — authoring the protobuf under proto/redpanda/core/admin/v2/, wiring it into the Bazel build, implementing the C++ service handler under src/v/redpanda/admin/services/, registering it on the admin server, and regenerating Python bindings for ducktape integration tests. Covers both new RPCs on an existing service and brand-new services.
# Add an Admin v2 ConnectRPC Endpoint This skill walks through every layer touched by a new admin v2 RPC: the `.proto`, the Bazel build, the C++ service implementation, registration on the admin server, and the Python bindings consumed by ducktape tests. For generic protobuf authoring conventions (field options, message design, well-known types), the canonical reference is `proto/redpanda/README.md`. This skill assumes you've read that and focuses on what's specific to admin v2. ## Reference example Commit `04d3160c3a` (`cluster: add manual upgrade finalization with admin v2 RPC`) is the cleanest minimal example — a new service with a single RPC. Skim these when unsure: - `proto/redpanda/core/admin/v2/features.proto` — the proto - `proto/redpanda/core/admin/v2/BUILD` — the BUILD entries (look at the `features_proto` / `features_redpanda_proto` pair) - `src/v/redpanda/admin/services/features.h` and `features.cc` — the C++ impl - `src/v/redpanda/admin/services/BUILD` — the `features` cc_library target - `src/v/redpanda/application_admin.cc` — the `add_service` registration `git show 04d3160c3a` will print the full diff. ## Procedure ### 1. Author the protobuf Create or extend a `.proto` under `proto/redpanda/core/admin/v2/`. One file per service domain; the filename matches the dominant service (`features.proto` → `FeaturesService`). Required header for a new file: ```proto // (BSL copyright header — copy from features.proto:1-13) syntax = "proto3"; package redpanda.core.admin.v2; import "proto/redpanda/core/pbgen/options.proto"; import "proto/redpanda/core/pbgen/rpc.proto"; option (pbgen.cpp_namespace) = "proto::admin"; ``` Notes: - `package` is always `redpanda.core.admin.v2` for admin v2. - `option (pbgen.cpp_namespace) = "proto::admin";` is mandatory and always exactly this value for admin v2 — the short form (`pbgen.cpp_namespace`, not the FQN `redpanda.core.pbgen.cpp_namespace`) is what's used in the tree. - Import `rpc.proto` only when the file defines a `service`. Service / RPC block: ```proto service MyService { // One short paragraph explaining what the RPC does and any // async/poll behavior the caller needs to know. rpc MyMethod(MyMethodRequest) returns (MyMethodResponse) { option (pbgen.rpc) = { authz: SUPERUSER }; } } message MyMethodRequest {} message MyMethodResponse {} ``` - Every RPC must carry `option (pbgen.rpc) = { authz: ... }`. Default to `SUPERUSER` for admin v2 — anything else (`USER`, `PUBLIC`) needs core-team approval (see `proto/redpanda/core/pbgen/rpc.proto`). - Optional `http_route: "/v2/..."` adds an alias HTTP path. The auto-generated `/<package>.<Service>/<Method>` route always works without it. - Naming: messages are `<RpcName>Request` / `<RpcName>Response`, one pair per RPC. Empty messages are fine. Field-level options worth knowing (full reference in `proto/redpanda/core/pbgen/options.proto`): - `[(pbgen.iobuf) = true]` on `string` fields that may exceed 128 KiB — generates `iobuf` instead of `ss::sstring`. `bytes` is already iobuf-backed. - `[(pbgen.ptr) = true]` on message fields for indirection (recursive types or when you need to distinguish unset). - `[debug_redact = true]` on sensitive fields — suppresses them from `fmt::formatter` output (passwords, tokens, etc.). Well-known types (`google.protobuf.Duration`, `Timestamp`, `FieldMask`) are supported; importing them requires the corresponding BUILD deps in step 2. ### 2. Wire up the Bazel build Each `.proto` needs **two stacked targets** in `proto/redpanda/core/admin/v2/BUILD`. Append (alphabetical order in the file): ```python proto_library( name = "myservice_proto", srcs = ["myservice.proto"], visibility = ["//visibility:public"], deps = [ "//proto/redpanda/core/pbgen:options_proto", "//proto/redpanda/core/pbgen:rpc_proto", # Add per-import: # "@protobuf//:timestamp_proto", # "@protobuf//:duration_proto", # "@protobuf//:field_mask_proto", # "@googleapis//google/api:field_info_proto", # "@googleapis//google/api:field_behavior_proto", # "@googleapis//google/api:resource_proto", # Cross-proto imports: e.g. ":kafka_connections_proto" ], ) redpanda_proto_library( name = "myservice_redpanda_proto", protos = [":myservice_proto"], visibility = ["//visibility:public"], deps = [ # Add when the proto uses Timestamp or Duration: # "@abseil-cpp//absl/time:time", # Add when the proto uses FieldMask: # "//src/v/serde/protobuf:field_mask", # For cross-proto deps the *_redpanda_proto sibling goes here: # ":kafka_connections_redpanda_proto" ], ) ``` Rules: - `proto_library.deps` mirrors `import` statements in the `.proto` file. - `redpanda_proto_library.deps` carries C++ deps the *generated* code needs (e.g. abseil for timestamps), plus any sibling `_redpanda_proto` targets for cross-proto imports. - The pbgen plugin lives at `bazel/pbgen/`; it generates `<name>.proto.h` and `<name>.proto.cc` with the message types, formatters, and service stubs. ### 3. Implement the C++ service If extending an existing service (just adding a new RPC), open the matching `src/v/redpanda/admin/services/<name>.{h,cc}` and add the new handler. Skip to step 4 after. For a brand-new service, create `src/v/redpanda/admin/services/<name>.h`: ```cpp /* * Copyright 2026 Redpanda Data, Inc. * (BSL header — copy from features.h:1-10) */ #pragma once #include "cluster/fwd.h" #include "proto/redpanda/core/admin/v2/<name>.proto.h" #include "redpanda/admin/proxy/client.h" namespace admin { class <name>_service_impl : public proto::admin::<name>_service { public: <name>_service_impl( admin::proxy::client, /* collaborators — e.g. cluster::controller*, ss::sharded<X>& */); ss::future<proto::admin::<rpc>_response> <rpc>( serde::pb::rpc::context, proto::admin::<rpc>_request) override; private: admin::proxy::client _proxy_client; /* members for collaborators */ }; } // namespace admin ``` Naming conventions (CamelCase → snake_case translation): - Service base class: `proto::admin::<service>_service` (e.g. `FeaturesService` → `features_service`) - Generated client (for inter-node proxying): `proto::admin::<service>_service_client` - Request / response types: `proto::admin::<rpc_name>_request` / `_response` - Handler method name: snake_case of the RPC name (e.g. `FinalizeUpgrade` → `finalize_upgrade`) - Implementation class: `admin::<service>_service_impl`, in namespace `admin` (NOT `proto::admin`) Handler signature is fixed: `ss::future<...response>` return type, `serde::pb::rpc::context` first arg, request second, `override`. Then `src/v/redpanda/admin/services/<name>.cc`: ```cpp #include "redpanda/admin/services/<name>.h" #include "redpanda/admin/services/utils.h" #include "serde/protobuf/rpc.h" #include <seastar/core/coroutine.hh> namespace admin { namespace { ss::logger <name>log{"admin_api_server/<name>_service"}; } // namespace <name>_service_impl::<name>_service_impl(/* args */) : _proxy_client(...) {} ss::future<proto::admin::<rpc>_response> <name>_service_impl::<rpc>( serde::pb::rpc::context ctx, proto::admin::<rpc>_request req) { vlog(<name>log.trace, "<rpc>: {}", req); // ... validate, optionally redirect-to-leader, do work ... co_return proto::admin::<rpc>_response{}; } } // namespace admin ``` Patterns to know — read the existing service files for live examples: - **Validation failures throw typed exceptions** declared in `src/v/serde/protobuf/rpc.h:241-287`: `invalid_argument_exception`, `failed_precondition_exception`, `not_found_exception`, `already_exists_exception`, `permission_denied_exception`, `unavailable_exception`, `unauthenticated_exception`, etc. Each maps to a ConnectRPC/gRPC status code. Example: `features.cc:46`. - **Leader redirect**: `admin::utils::redirect_to_leader(...)` from `services/utils.h` returns an optional `node_id`; if set, proxy the call to that node using the generated `_service_client`. Pattern in `features.cc:51-64`. - **Proxying to peers**: `_proxy_client.make_client_for_node<proto::admin::<service>_service_client>(node)` for one target, or `.make_clients_for_other_nodes<...>()` for scatter-gather. Defined in `redpanda/admin/proxy/client.h`. - **License gating**: `admin::utils::check_license(_feature_table.local())` if the RPC is enterprise-gated. See `cluster.cc:51`. - **Avoid proxy loops** in scatter-gather handlers: gate with `proxy::is_proxied(ctx)` (example in `cluster.cc:56`). Add the BUILD entry to `src/v/redpanda/admin/services/BUILD`: ```python redpanda_cc_library( name = "<name>", srcs = ["<name>.cc"], hdrs = ["<name>.h"], implementation_deps = [ ":utils", # .cc-only collaborators ], deps = [ "//proto/redpanda/core/admin/v2:<name>_redpanda_proto", "//src/v/cluster:fwd", "//src/v/redpanda/admin/proxy:client", "//src/v/serde/protobuf:rpc", "@seastar", # types that appear in <name>.h ], ) ``` Rule: types that appear in the `.h` belong in `deps`; collaborators only used in the `.cc` belong in `implementation_deps`. ### 4. Register the service Two edits in `src/v/redpanda/`: **4a. `src/v/redpanda/BUILD`** — add the new services library to the top-level `redpanda` library's `deps` list (kept sorted): ```python "//src/v/redpanda/admin/services:<name>", ``` **4b. `src/v/redpanda/application_admin.cc`** — two changes: 1. Include the header (alphabetical with the other service includes): ```cpp #include "redpanda/admin/services/<name>.h" ``` 2. Inside `_admin.invoke_on_all([this, node_id](admin_server& s) { ... })`, append an `add_service` call. `create_client()` is the local lambda defined at the top of the block; pass other collaborators via `controller.get()` or `std::ref(...)`: ```cpp s.add_service( std::make_unique<admin::<name>_service_impl>( create_client(), /* collaborators */)); ``` That's it for registration. `add_service` walks the service's routes and registers an HTTP POST handler per route at `route.path` with the auth wrapper keyed on `route.authz_level`. ### 5. Build and format ```bash bazel build //proto/redpanda/core/admin/v2:<name>_redpanda_proto bazel build //src/v/redpanda/admin/services:<name> bazel build //src/v/redpanda:application bazel run //tools:clang_format ``` Fix compilation errors before moving on. The pbgen plugin's error messages are usually self-explanatory; common causes are missing BUILD deps from step 2 or imports in the `.proto` without matching `proto_library.deps`. ### 6. Regenerate ducktape Python bindings Ducktape tests consume admin v2 via committed-to-repo Python bindings under `tests/rptest/clients/admin/proto/`. They are regenerated by a script — CI (`.github/workflows/check-ducktape-protos.yml`) fails the PR if they're stale, so this step is mandatory whenever a `.proto` under `proto/redpanda/core/admin/**` changes. Prerequisite: `uv` installed (https://docs.astral.sh/uv/getting-started/installation/). The script aborts otherwise. ```bash
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen