From c12bf20dea88a39df0d818ad398be3cc170285d0 Mon Sep 17 00:00:00 2001 From: Alex Lyn Date: Sat, 4 Apr 2026 11:22:49 +0200 Subject: [PATCH] pod-resources-rs: Add kubelet Pod Resources API client MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a gRPC client crate that speaks the kubelet PodResourcesLister service (v1). The runtime-rs VFIO cold-plug path needs this to discover which GPU devices the kubelet has assigned to a pod so they can be passed through to the guest before the VM boots. The crate is intentionally kept minimal: it wraps the upstream pod_resources.proto, exposes a Unix-domain-socket client, and re-exports the generated types. Signed-off-by: Alex Lyn Signed-off-by: Fabiano FidĂȘncio --- .github/workflows/build-checks.yaml | 1 + Cargo.toml | 2 + src/libs/pod-resources-rs/Cargo.toml | 22 ++ src/libs/pod-resources-rs/build.rs | 16 + .../proto/pod_resources.proto | 117 +++++++ src/libs/pod-resources-rs/src/lib.rs | 84 +++++ .../pod-resources-rs/src/pod_resources/mod.rs | 120 +++++++ .../pod-resources-rs/src/pod_resources/v1.rs | 301 ++++++++++++++++++ 8 files changed, 663 insertions(+) create mode 100644 src/libs/pod-resources-rs/Cargo.toml create mode 100644 src/libs/pod-resources-rs/build.rs create mode 100644 src/libs/pod-resources-rs/proto/pod_resources.proto create mode 100644 src/libs/pod-resources-rs/src/lib.rs create mode 100644 src/libs/pod-resources-rs/src/pod_resources/mod.rs create mode 100644 src/libs/pod-resources-rs/src/pod_resources/v1.rs diff --git a/.github/workflows/build-checks.yaml b/.github/workflows/build-checks.yaml index f8259fd5fb..1de6df5435 100644 --- a/.github/workflows/build-checks.yaml +++ b/.github/workflows/build-checks.yaml @@ -48,6 +48,7 @@ jobs: path: src/runtime-rs needs: - rust + - protobuf-compiler - name: libs path: src/libs needs: diff --git a/Cargo.toml b/Cargo.toml index 220909b358..507f6726ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ members = [ "src/libs/kata-types", "src/libs/logging", "src/libs/mem-agent", + "src/libs/pod-resources-rs", "src/libs/protocols", "src/libs/runtime-spec", "src/libs/safe-path", @@ -117,6 +118,7 @@ wasm_container = { path = "src/runtime-rs/crates/runtimes/wasm_container" } # Local dependencies from `src/lib` kata-sys-util = { path = "src/libs/kata-sys-util" } +pod-resources-rs = { path = "src/libs/pod-resources-rs" } kata-types = { path = "src/libs/kata-types", features = ["safe-path"] } logging = { path = "src/libs/logging" } mem-agent = { path = "src/libs/mem-agent" } diff --git a/src/libs/pod-resources-rs/Cargo.toml b/src/libs/pod-resources-rs/Cargo.toml new file mode 100644 index 0000000000..fa78597610 --- /dev/null +++ b/src/libs/pod-resources-rs/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "pod-resources-rs" +version = "0.1.0" +edition = "2024" + +[dependencies] +anyhow = "1.0.100" +tokio = "1.48" +tokio-util = "0.7.17" +tower = "0.5" +hyper-util = { version = "0.1", features = ["tokio"] } +# gRPC dependencies for kubelet pod-resources API +tonic = "0.14" +prost = "0.14" +tonic-prost = "0.14" +oci-spec = { version = "0.8.1", features = ["runtime"] } +container-device-interface = "0.1.2" +slog = "2.5.2" +slog-scope = "4.4.0" + +[build-dependencies] +tonic-prost-build = "0.14" diff --git a/src/libs/pod-resources-rs/build.rs b/src/libs/pod-resources-rs/build.rs new file mode 100644 index 0000000000..539d0adb1d --- /dev/null +++ b/src/libs/pod-resources-rs/build.rs @@ -0,0 +1,16 @@ +// Copyright (c) 2026 Ant Group +// +// SPDX-License-Identifier: Apache-2.0 +// + +/// This generates Device Plugin code (in v1beta1.rs) from pluginapi.proto +fn main() -> Result<(), Box> { + tonic_prost_build::configure() + .build_server(false) // We only need the client + .build_client(true) + .out_dir("src/pod_resources") + .compile_protos(&["proto/pod_resources.proto"], &["proto"]) + .expect("failed to compile protos"); + + Ok(()) +} diff --git a/src/libs/pod-resources-rs/proto/pod_resources.proto b/src/libs/pod-resources-rs/proto/pod_resources.proto new file mode 100644 index 0000000000..6a98abd7ca --- /dev/null +++ b/src/libs/pod-resources-rs/proto/pod_resources.proto @@ -0,0 +1,117 @@ +// To regenerate api.pb.go run `hack/update-codegen.sh protobindings` +syntax = "proto3"; + +package v1; +option go_package = "k8s.io/kubelet/pkg/apis/podresources/v1"; + + +// PodResourcesLister is a service provided by the kubelet that provides information about the +// node resources consumed by pods and containers on the node +service PodResourcesLister { + /// List returns the node resources assigned to pods and containers. + rpc List(ListPodResourcesRequest) returns (ListPodResourcesResponse) {} + /// GetAllocatableResources returns the node resources that are available for assignment to pods and containers. + rpc GetAllocatableResources(AllocatableResourcesRequest) returns (AllocatableResourcesResponse) {} + /// Get returns the node resources assigned to a specific pod. + rpc Get(GetPodResourcesRequest) returns (GetPodResourcesResponse) {} +} + +// AllocatableResourcesRequest is the request made to the GetAllocatableResources service +message AllocatableResourcesRequest {} + +// AllocatableResourcesResponses contains informations about all the devices known by the kubelet +message AllocatableResourcesResponse { + repeated ContainerDevices devices = 1; + repeated int64 cpu_ids = 2; + repeated ContainerMemory memory = 3; +} + +// ListPodResourcesRequest is the request made to the PodResources service +message ListPodResourcesRequest {} + +// ListPodResourcesResponse is the response returned by List function +message ListPodResourcesResponse { + repeated PodResources pod_resources = 1; +} + +// GetPodResourcesRequest is the request made to the Get service +message GetPodResourcesRequest { + string pod_name = 1; + string pod_namespace = 2; +} + +// GetPodResourcesResponse is the response returned by Get function +message GetPodResourcesResponse { + PodResources pod_resources = 1; +} + +// PodResources contains information about the node resources assigned to a pod +message PodResources { + string name = 1; + string namespace = 2; + repeated ContainerResources containers = 3; +} + +// ContainerResources contains information about the resources assigned to a container +message ContainerResources { + string name = 1; + repeated ContainerDevices devices = 2; + repeated int64 cpu_ids = 3; + repeated ContainerMemory memory = 4; + repeated DynamicResource dynamic_resources = 5; +} + +// ContainerDevices contains information about the devices assigned to a container +message ContainerDevices { + string resource_name = 1; + repeated string device_ids = 2; + TopologyInfo topology = 3; +} + +// ContainerMemory contains information about memory and hugepages assigned to a container +message ContainerMemory { + string memory_type = 1; + uint64 size = 2; + TopologyInfo topology = 3; +} + +// DynamicResource contains information about the devices assigned to a container by DRA +message DynamicResource { + // tombstone: removed in 1.31 because claims are no longer associated with one class + // string class_name = 1; + string claim_name = 2; + string claim_namespace = 3; + repeated ClaimResource claim_resources = 4; +} + +// ClaimResource contains resource information. The driver name/pool name/device name +// triplet uniquely identifies the device. Should DRA get extended to other kinds +// of resources, then device_name will be empty and other fields will get added. +// Each device at the DRA API level may map to zero or more CDI devices. +message ClaimResource { + repeated CDIDevice cdi_devices = 1; + string driver_name = 2; + string pool_name = 3; + string device_name = 4; +} + +// Topology describes hardware topology of the resource +message TopologyInfo { + repeated NUMANode nodes = 1; +} + +// NUMA representation of NUMA node +message NUMANode { + int64 ID = 1; +} + +// CDIDevice specifies a CDI device information +message CDIDevice { + // Fully qualified CDI device name + // for example: vendor.com/gpu=gpudevice1 + // see more details in the CDI specification: + // https://github.com/container-orchestrated-devices/container-device-interface/blob/main/SPEC.md + string name = 1; +} + + diff --git a/src/libs/pod-resources-rs/src/lib.rs b/src/libs/pod-resources-rs/src/lib.rs new file mode 100644 index 0000000000..476e7bf23e --- /dev/null +++ b/src/libs/pod-resources-rs/src/lib.rs @@ -0,0 +1,84 @@ +// Copyright (c) 2026 Ant Group +// +// SPDX-License-Identifier: Apache-2.0 +// + +pub mod pod_resources; + +use anyhow::{Result, anyhow}; +use cdi::specs::config::DeviceNode; +// use cdi::container_edits::DeviceNode; +use cdi::cache::{CdiOption, new_cache, with_auto_refresh}; +use cdi::spec_dirs::with_spec_dirs; +use container_device_interface as cdi; + +use slog::info; +use std::sync::Arc; +use tokio::time; + +/// DEFAULT_DYNAMIC_CDI_SPEC_PATH is the default directory for dynamic CDI Specs, +/// which can be overridden by specifying a different path when creating the cache. +const DEFAULT_DYNAMIC_CDI_SPEC_PATH: &str = "/var/run/cdi"; +/// DEFAULT_STATIC_CDI_SPEC_PATH is the default directory for static CDI Specs, +/// which can be overridden by specifying a different path when creating the cache. +const DEFAULT_STATIC_CDI_SPEC_PATH: &str = "/etc/cdi"; + +#[macro_export] +macro_rules! sl { + () => { + slog_scope::logger() + }; +} + +pub async fn handle_cdi_devices( + devices: &[String], + _cdi_timeout: time::Duration, +) -> Result> { + if devices.is_empty() { + info!(sl!(), "no pod CDI devices requested."); + return Ok(vec![]); + } + // Explicitly set the cache options to disable auto-refresh and + // to use the default spec dirs for dynamic and static CDI Specs + let options: Vec = vec![ + with_auto_refresh(false), + with_spec_dirs(&[DEFAULT_DYNAMIC_CDI_SPEC_PATH, DEFAULT_STATIC_CDI_SPEC_PATH]), + ]; + let cache: Arc> = new_cache(options); + + let target_devices = { + let mut target_devices = vec![]; + // Lock cache within this scope, std::sync::Mutex has no Send + // and await will not work with time::sleep + let mut cache = cache.lock().unwrap(); + match cache.refresh() { + Ok(_) => {} + Err(e) => { + return Err(anyhow!("Refreshing cache failed: {:?}", e)); + } + } + + for dev in devices.iter() { + info!(sl!(), "Requested CDI device with FQN: {}", dev); + match cache.get_device(dev) { + Some(device) => { + info!(sl!(), "Target CDI device: {}", device.get_qualified_name()); + if let Some(devnodes) = device.edits().container_edits.device_nodes { + target_devices.extend(devnodes.iter().cloned()); + } + } + None => { + return Err(anyhow!( + "Failed to get device node for CDI device: {} in cache", + dev + )); + } + } + } + + target_devices + }; + info!(sl!(), "target CDI devices to inject: {:?}", target_devices); + + Ok(target_devices) +} diff --git a/src/libs/pod-resources-rs/src/pod_resources/mod.rs b/src/libs/pod-resources-rs/src/pod_resources/mod.rs new file mode 100644 index 0000000000..f83a3f0e95 --- /dev/null +++ b/src/libs/pod-resources-rs/src/pod_resources/mod.rs @@ -0,0 +1,120 @@ +// Copyright (c) 2026 Ant Group +// +// SPDX-License-Identifier: Apache-2.0 +// + +pub mod v1; + +use v1::pod_resources_lister_client::PodResourcesListerClient; + +use std::collections::HashMap; + +use anyhow::{Context, Result, anyhow}; +use hyper_util::rt::TokioIo; +use tokio::net::UnixStream; +use tokio::time::{Duration, timeout}; +use tonic::transport::{Channel, Endpoint, Uri}; +use tower::service_fn; + +use crate::pod_resources::v1::GetPodResourcesRequest; +const SANDBOX_NAME_ANNOTATION: &str = "io.kubernetes.cri.sandbox-name"; +const SANDBOX_NAMESPACE_ANNOTATION: &str = "io.kubernetes.cri.sandbox-namespace"; +pub const DEFAULT_POD_RESOURCES_PATH: &str = "/var/lib/kubelet/pod-resources"; +pub const DEFAULT_POD_RESOURCES_TIMEOUT: Duration = Duration::from_secs(10); +pub const CDI_K8S_PREFIX: &str = "cdi.k8s.io/"; +const MAX_RECV_MSG_SIZE: usize = 16 * 1024 * 1024; // 16MB + +// Create a gRPC channel to the specified Unix socket +async fn create_grpc_channel(socket_path: &str) -> Result { + let socket_path = socket_path.trim_start_matches("unix://"); + let socket_path_owned = socket_path.to_string(); + + // Create a gRPC endpoint with a timeout + let endpoint = Endpoint::try_from("http://[::]:50051") + .context("failed to create endpoint")? + .timeout(DEFAULT_POD_RESOURCES_TIMEOUT); + + // Connect to the Unix socket using a custom connector + let channel = endpoint + .connect_with_connector(service_fn(move |_: Uri| { + let socket_path = socket_path_owned.clone(); + async move { + let stream = UnixStream::connect(&socket_path).await.map_err(|e| { + std::io::Error::new( + e.kind(), + format!("failed to connect to {}: {}", socket_path, e), + ) + })?; + Ok::<_, std::io::Error>(TokioIo::new(stream)) + } + })) + .await + .context("failed to connect to unix socket")?; + + Ok(channel) +} + +pub async fn get_pod_cdi_devices( + socket: &str, + annotations: &HashMap, +) -> Result> { + let pod_name = annotations.get(SANDBOX_NAME_ANNOTATION).ok_or_else(|| { + anyhow::anyhow!("cold plug: missing annotation {}", SANDBOX_NAME_ANNOTATION) + })?; + + let pod_namespace = annotations + .get(SANDBOX_NAMESPACE_ANNOTATION) + .ok_or_else(|| { + anyhow::anyhow!( + "cold plug: missing annotation {}", + SANDBOX_NAMESPACE_ANNOTATION + ) + })?; + + // Create gRPC channel to kubelet pod-resources socket + let channel = create_grpc_channel(socket) + .await + .context("cold plug: failed to connect to kubelet")?; + + // Create PodResourcesLister client + let mut client = PodResourcesListerClient::new(channel) + .max_decoding_message_size(MAX_RECV_MSG_SIZE) + .max_encoding_message_size(MAX_RECV_MSG_SIZE); + + // Prepare and send GetPodResources request + let request = tonic::Request::new(GetPodResourcesRequest { + pod_name: pod_name.to_string(), + pod_namespace: pod_namespace.to_string(), + }); + + // Await response with timeout + let response = timeout(DEFAULT_POD_RESOURCES_TIMEOUT, client.get(request)) + .await + .context("cold plug: GetPodResources timeout")? + .context("cold plug: GetPodResources RPC failed")?; + + // Extract PodResources from response + let pod_resources = response + .into_inner() + .pod_resources + .ok_or_else(|| anyhow!("cold plug: PodResources is nil"))?; + + // Format device specifications + let format_cdi_device_ids = |resource_name: &str, device_ids: &[String]| -> Vec { + device_ids + .iter() + .map(|id| format!("{}={}", resource_name, id)) + .collect() + }; + + // Collect all device specifications from all containers + let mut devices = Vec::new(); + for container in &pod_resources.containers { + for device in &container.devices { + let cdi_devices = format_cdi_device_ids(&device.resource_name, &device.device_ids); + devices.extend(cdi_devices); + } + } + + Ok(devices) +} diff --git a/src/libs/pod-resources-rs/src/pod_resources/v1.rs b/src/libs/pod-resources-rs/src/pod_resources/v1.rs new file mode 100644 index 0000000000..ace7635a68 --- /dev/null +++ b/src/libs/pod-resources-rs/src/pod_resources/v1.rs @@ -0,0 +1,301 @@ +// This file is @generated by prost-build. +/// AllocatableResourcesRequest is the request made to the GetAllocatableResources service +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] +pub struct AllocatableResourcesRequest {} +/// AllocatableResourcesResponses contains informations about all the devices known by the kubelet +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AllocatableResourcesResponse { + #[prost(message, repeated, tag = "1")] + pub devices: ::prost::alloc::vec::Vec, + #[prost(int64, repeated, tag = "2")] + pub cpu_ids: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "3")] + pub memory: ::prost::alloc::vec::Vec, +} +/// ListPodResourcesRequest is the request made to the PodResources service +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] +pub struct ListPodResourcesRequest {} +/// ListPodResourcesResponse is the response returned by List function +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListPodResourcesResponse { + #[prost(message, repeated, tag = "1")] + pub pod_resources: ::prost::alloc::vec::Vec, +} +/// GetPodResourcesRequest is the request made to the Get service +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct GetPodResourcesRequest { + #[prost(string, tag = "1")] + pub pod_name: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub pod_namespace: ::prost::alloc::string::String, +} +/// GetPodResourcesResponse is the response returned by Get function +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetPodResourcesResponse { + #[prost(message, optional, tag = "1")] + pub pod_resources: ::core::option::Option, +} +/// PodResources contains information about the node resources assigned to a pod +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PodResources { + #[prost(string, tag = "1")] + pub name: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub namespace: ::prost::alloc::string::String, + #[prost(message, repeated, tag = "3")] + pub containers: ::prost::alloc::vec::Vec, +} +/// ContainerResources contains information about the resources assigned to a container +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ContainerResources { + #[prost(string, tag = "1")] + pub name: ::prost::alloc::string::String, + #[prost(message, repeated, tag = "2")] + pub devices: ::prost::alloc::vec::Vec, + #[prost(int64, repeated, tag = "3")] + pub cpu_ids: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "4")] + pub memory: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "5")] + pub dynamic_resources: ::prost::alloc::vec::Vec, +} +/// ContainerDevices contains information about the devices assigned to a container +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ContainerDevices { + #[prost(string, tag = "1")] + pub resource_name: ::prost::alloc::string::String, + #[prost(string, repeated, tag = "2")] + pub device_ids: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, + #[prost(message, optional, tag = "3")] + pub topology: ::core::option::Option, +} +/// ContainerMemory contains information about memory and hugepages assigned to a container +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ContainerMemory { + #[prost(string, tag = "1")] + pub memory_type: ::prost::alloc::string::String, + #[prost(uint64, tag = "2")] + pub size: u64, + #[prost(message, optional, tag = "3")] + pub topology: ::core::option::Option, +} +/// DynamicResource contains information about the devices assigned to a container by DRA +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct DynamicResource { + /// tombstone: removed in 1.31 because claims are no longer associated with one class + /// string class_name = 1; + #[prost(string, tag = "2")] + pub claim_name: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub claim_namespace: ::prost::alloc::string::String, + #[prost(message, repeated, tag = "4")] + pub claim_resources: ::prost::alloc::vec::Vec, +} +/// ClaimResource contains resource information. The driver name/pool name/device name +/// triplet uniquely identifies the device. Should DRA get extended to other kinds +/// of resources, then device_name will be empty and other fields will get added. +/// Each device at the DRA API level may map to zero or more CDI devices. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ClaimResource { + #[prost(message, repeated, tag = "1")] + pub cdi_devices: ::prost::alloc::vec::Vec, + #[prost(string, tag = "2")] + pub driver_name: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub pool_name: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub device_name: ::prost::alloc::string::String, +} +/// Topology describes hardware topology of the resource +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TopologyInfo { + #[prost(message, repeated, tag = "1")] + pub nodes: ::prost::alloc::vec::Vec, +} +/// NUMA representation of NUMA node +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] +pub struct NumaNode { + #[prost(int64, tag = "1")] + pub id: i64, +} +/// CDIDevice specifies a CDI device information +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct CdiDevice { + /// Fully qualified CDI device name + /// for example: vendor.com/gpu=gpudevice1 + /// see more details in the CDI specification: + /// + #[prost(string, tag = "1")] + pub name: ::prost::alloc::string::String, +} +/// Generated client implementations. +pub mod pod_resources_lister_client { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// PodResourcesLister is a service provided by the kubelet that provides information about the + /// node resources consumed by pods and containers on the node + #[derive(Debug, Clone)] + pub struct PodResourcesListerClient { + inner: tonic::client::Grpc, + } + impl PodResourcesListerClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl PodResourcesListerClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> PodResourcesListerClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + std::marker::Send + std::marker::Sync, + { + PodResourcesListerClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// / List returns the node resources assigned to pods and containers. + pub async fn list( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/v1.PodResourcesLister/List", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("v1.PodResourcesLister", "List")); + self.inner.unary(req, path, codec).await + } + /// / GetAllocatableResources returns the node resources that are available for assignment to pods and containers. + pub async fn get_allocatable_resources( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/v1.PodResourcesLister/GetAllocatableResources", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("v1.PodResourcesLister", "GetAllocatableResources"), + ); + self.inner.unary(req, path, codec).await + } + /// / Get returns the node resources assigned to a specific pod. + pub async fn get( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/v1.PodResourcesLister/Get", + ); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("v1.PodResourcesLister", "Get")); + self.inner.unary(req, path, codec).await + } + } +}