Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/control-plane-services/function-autoscaler/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ cargo test -p rs-autoscaler
cargo deny check advisories
```

`crates/server` depends on `//src/libraries/rust/nvcf-info` as a Bazel target
only, so the cargo commands above do not resolve it. Build and test that crate
with Bazel from the monorepo root:

```bash
bazel test //src/control-plane-services/function-autoscaler/crates/server:all
```

CI subproject id: `function-autoscaler`. Native Bazel validation and release
wiring live in `tools/ci/subproject-validations.yaml`, an internal GitLab CI
config not present in this public snapshot.
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,30 @@ load("@rules_rust//cargo:defs.bzl", "cargo_build_script")
load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_library", "rust_test")
load("//rules/oci:defs.bzl", "rust_oci_image")

# Stamp the real release version into the binary so CARGO_PKG_VERSION (used by
# `--version`, startup logs, and the OTel service.version resource attribute)
# reflects the released image tag instead of the placeholder 0.0.0-dev. The
# Stamp the real release version and commit into the binary so
# CARGO_PKG_VERSION (used by `--version`, startup logs, the OTel
# service.version resource attribute, and the GET /info handler) reflects the
# released image tag instead of the placeholder 0.0.0-dev, and NVCF_GIT_COMMIT
# (consumed by GET /info) reflects the real commit instead of "unknown". The
# legacy Dockerfile did this via CICD_NEXT_VERSION -> build.rs; the Bazel build
# dropped it. tools/workspace_status.sh emits STABLE_VERSION; expand_template
# substitutes it on --stamp (release) builds and falls back to 0.0.0-dev
# otherwise. Fed to the Rust targets via rustc_env_files.
# dropped it. tools/workspace_status.sh emits STABLE_VERSION/STABLE_GIT_COMMIT_FULL;
# expand_template substitutes them on --stamp (release) builds and falls back
# to dev defaults otherwise. Fed to the Rust targets via rustc_env_files.
expand_template(
name = "version_env",
out = "version.env",
stamp_substitutions = {"{VERSION}": "{{STABLE_VERSION}}"},
substitutions = {"{VERSION}": "0.0.0-dev"},
template = ["CARGO_PKG_VERSION={VERSION}"],
stamp_substitutions = {
"{VERSION}": "{{STABLE_VERSION}}",
"{GIT_COMMIT}": "{{STABLE_GIT_COMMIT_FULL}}",
},
substitutions = {
"{VERSION}": "0.0.0-dev",
"{GIT_COMMIT}": "unknown",
},
template = [
"CARGO_PKG_VERSION={VERSION}",
"NVCF_GIT_COMMIT={GIT_COMMIT}",
],
)

# build.rs uses tonic-build + prost-build to compile crates/server/proto/nvcf.proto.
Expand Down Expand Up @@ -61,7 +72,10 @@ rust_library(
proc_macro_deps = all_crate_deps(proc_macro = True),
rustc_env_files = [":version_env"],
visibility = ["//visibility:public"],
deps = [":build_script"] + all_crate_deps(normal = True),
deps = [
":build_script",
"//src/libraries/rust/nvcf-info:nvcf-info-autoscaler",
] + all_crate_deps(normal = True),
)

rust_binary(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ impl From<ComponentHealth> for ComponentHealthResponse {
}
}

/// Build metadata. Version and commit are stamped by the version_env template
/// in crates/server/BUILD.bazel on --stamp builds.
pub async fn get_info() -> Json<nvcf_info::InfoResponse> {
Json(nvcf_info::info_response!("nvcf-function-autoscaler"))
}

/// Liveness: process is alive. No dependency checks.
/// Used by Kubernetes liveness probe. Failure causes pod restart.
/// We intentionally do not check TimeseriesDb/Cassandra here — restarting when they're
Expand Down Expand Up @@ -124,6 +130,17 @@ mod tests {
assert_eq!(result.unwrap_err(), StatusCode::SERVICE_UNAVAILABLE);
}

#[tokio::test]
async fn info_reports_service_version_and_commit() {
let Json(info) = get_info().await;
assert_eq!(info.service, "nvcf-function-autoscaler");
// Stamped only on Bazel --stamp builds; under cargo these are the
// unstamped fallbacks. Assert they are populated, not their literals,
// so the test does not break on every release bump.
assert!(!info.version.is_empty());
assert!(!info.commit.is_empty());
}

#[tokio::test]
async fn readiness_returns_200_once_all_components_healthy() {
let health = Arc::new(Health::new());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {

// Main app on 8080
let app = Router::new()
.route("/info", get(routes::get_info))
.route("/health", get(routes::get_health))
.route("/admin/health/liveness", get(routes::get_liveness))
.route("/admin/health/readiness", get(routes::get_readiness))
Expand Down
4 changes: 4 additions & 0 deletions src/invocation-plane-services/http-invocation/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ cargo run --package nvcf-invocation-service --bin server --release -- \
The staging-local config connects to staging NVCF. Keep secrets and bearer
tokens out of committed config and examples.

`crates/server` depends on `//src/libraries/rust/nvcf-info` as a Bazel target
only, so plain cargo builds of that crate do not resolve it. Use `bazel build`
and `bazel test` for it instead.

## Local Gotchas

- `MODULE.bazel` owns the Rust toolchain, `rules_rust`, `crate_universe`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,33 @@ load("@rules_rust//cargo:defs.bzl", "cargo_build_script")
load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_library", "rust_test")
load("//rules/oci:defs.bzl", "rust_oci_image")

# Stamp the real release version into the binary. The legacy Dockerfile did
# this via the CICD_NEXT_VERSION build-arg -> build.rs -> CARGO_PKG_VERSION; the
# Bazel build dropped it, so binaries self-reported the placeholder version
# (e.g. `server --version`, startup logs, and the OTel service.version resource
# attribute all showed 0.0.0-dev regardless of the released image tag).
# tools/workspace_status.sh emits STABLE_VERSION; expand_template substitutes it
# on `--stamp` (release) builds and falls back to 0.0.0-dev otherwise. The file
# is fed to the Rust targets via rustc_env_files so env!("CARGO_PKG_VERSION")
# resolves to the release version.
# Stamp the real release version and commit into the binary. The legacy
# Dockerfile did this via the CICD_NEXT_VERSION build-arg -> build.rs ->
# CARGO_PKG_VERSION; the Bazel build dropped it, so binaries self-reported the
# placeholder version (e.g. `server --version`, startup logs, and the OTel
# service.version resource attribute all showed 0.0.0-dev regardless of the
# released image tag). tools/workspace_status.sh emits
# STABLE_VERSION/STABLE_GIT_COMMIT_FULL; expand_template substitutes them on
# `--stamp` (release) builds and falls back to dev defaults otherwise. The
# file is fed to the Rust targets via rustc_env_files so
# env!("CARGO_PKG_VERSION") resolves to the release version and the GET /info
# handler's NVCF_GIT_COMMIT (via option_env!, see the shared nvcf-info crate)
# resolves to the real commit.
expand_template(
name = "version_env",
out = "version.env",
stamp_substitutions = {"{VERSION}": "{{STABLE_VERSION}}"},
substitutions = {"{VERSION}": "0.0.0-dev"},
template = ["CARGO_PKG_VERSION={VERSION}"],
stamp_substitutions = {
"{VERSION}": "{{STABLE_VERSION}}",
"{GIT_COMMIT}": "{{STABLE_GIT_COMMIT_FULL}}",
},
substitutions = {
"{VERSION}": "0.0.0-dev",
"{GIT_COMMIT}": "unknown",
},
template = [
"CARGO_PKG_VERSION={VERSION}",
"NVCF_GIT_COMMIT={GIT_COMMIT}",
],
)

# build.rs uses tonic-build + prost-build to compile crates/server/proto/*.proto.
Expand Down Expand Up @@ -77,7 +89,10 @@ rust_library(
rustc_env = {"CARGO_PKG_NAME": "nvcf-invocation-service"},
rustc_env_files = [":version_env"],
visibility = ["//visibility:public"],
deps = [":build_script"] + all_crate_deps(normal = True),
deps = [
":build_script",
"//src/libraries/rust/nvcf-info:nvcf-info-invocation",
] + all_crate_deps(normal = True),
)

rust_binary(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ pub async fn app(
)
.layer(axum_mw::from_fn(nvcf_mw::auth::auth_middleware)) // Everything above this layer will require auth DON'T MOVE IT
.route("/health", get(routes::get_health)) // Needs to be ahead of other layers to avoid auth, and after metrics layer to get recorded
.route("/info", get(routes::get_info)) // unauthenticated, same as /health above
.layer(CorsLayer::very_permissive().max_age(Duration::from_secs(86400))) // only on the path based router. for full path passthrough we send the OPTIONS and all other requests all the way to the worker.
.layer(
PrometheusMetricLayerBuilder::new()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use axum::Json;

pub async fn get_info() -> Json<nvcf_info::InfoResponse> {
Json(nvcf_info::info_response!("nvcf-invocation-service"))
}

#[cfg(test)]
mod tests {
use super::*;

#[tokio::test]
async fn info_reports_service_version_and_commit() {
let Json(info) = get_info().await;
assert_eq!(info.service, "nvcf-invocation-service");
// Stamped only on Bazel --stamp builds; under cargo these are the
// unstamped fallbacks. Assert they are populated, not their literals,
// so the test does not break on every release bump.
assert!(!info.version.is_empty());
assert!(!info.commit.is_empty());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ mod get_exec;
mod get_pexec;
mod health;
mod http_headers;
mod info;
mod input_asset_header;
mod nvcf_status_header;
mod post_exec;
Expand All @@ -31,6 +32,7 @@ pub use attach::post_attach::response_attach;
pub use get_exec::exec_status;
pub use get_pexec::pexec_status_route;
pub use health::get_health;
pub use info::get_info;
pub use post_exec::exec;
pub use post_exec::{InvokeFunctionResponse, InvokeStatus};
pub use post_pexec::pexec;
Expand Down
47 changes: 47 additions & 0 deletions src/libraries/rust/nvcf-info/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# AGENTS.md - nvcf-info

nvcf-info holds the shared `GET /info` response schema for the Rust services,
so `function-autoscaler` and `http-invocation` do not each define their own.
It is the Rust counterpart to `src/libraries/go/lib/pkg/version` and the Java
`nv-boot-starter-core` info controller.

## Usage

```rust
async fn get_info() -> axum::Json<nvcf_info::InfoResponse> {
axum::Json(nvcf_info::info_response!("nvcf-my-service"))
}
```

Pass the deployed service name, matching how the Go services set
`version.Service` in their `BUILD.bazel` `x_defs`. Version and commit come from
the consuming service's `version_env` template in `crates/server/BUILD.bazel`,
which stamps `CARGO_PKG_VERSION` and `NVCF_GIT_COMMIT` on `--stamp` builds.

## Adding A Consumer

Add the service's Bazel target to `crates/server/BUILD.bazel` `deps`, and add
an entry to the list in this crate's `BUILD.bazel` if the service uses a
crate universe not already listed there. Two serde copies are two distinct
`Serialize` traits, so each universe needs its own build of `src/lib.rs`.

This crate is a Bazel dependency only. It is not a Cargo path dependency:
`cargo-bazel splice` roots each service workspace in a temp dir, so a path
pointing outside that directory resolves above the splice root. Consuming
crates therefore build and test under Bazel rather than cargo.

## Build And Test

Run Bazel from the monorepo root:

```bash
bazel test //src/libraries/rust/nvcf-info:all
```

Cargo works inside this crate, which has no cross-workspace path dependencies:

```bash
cargo fmt -p nvcf-info
cargo clippy -p nvcf-info --all-targets -- -D warnings
cargo test -p nvcf-info
```
33 changes: 33 additions & 0 deletions src/libraries/rust/nvcf-info/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# SPDX-FileCopyrightText: Copyright (c) NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

load("@rules_rust//rust:defs.bzl", "rust_library", "rust_test")

# One target per consuming crate universe. Each Rust service resolves serde
# from its own crate_universe repo, and two serde copies are two distinct
# Serialize traits, so a single shared target fails at the axum::Json bound in
# whichever service it was not built against. Add an entry here for any new
# consumer. See src/libraries/rust/nvcf-info/AGENTS.md.
[
rust_library(
name = "nvcf-info-%s" % universe,
srcs = ["src/lib.rs"],
crate_name = "nvcf_info",
edition = "2021",
visibility = ["//visibility:public"],
deps = ["@%s//:serde" % repo],
)
for universe, repo in [
("autoscaler", "rs_autoscaler_crates"),
("invocation", "nvcf_invocation_crates"),
]
]

rust_test(
name = "nvcf_info_test",
crate = ":nvcf-info-autoscaler",
deps = [
"@rs_autoscaler_crates//:serde",
"@rs_autoscaler_crates//:serde_json",
],
)
1 change: 1 addition & 0 deletions src/libraries/rust/nvcf-info/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@AGENTS.md
Loading
Loading