runtime-rs: impl volume-resize trait for sandbox

Implements resize-volume handlers in shim-mgmt,
trait for sandbox and add RPC calls to agent.
Note the actual rpc handler for the resize request is currently not
implemented, refer to issue #3694.

Fixes #5369

Signed-off-by: Tingzhou Yuan <tzyuan15@bu.edu>
This commit is contained in:
Tingzhou Yuan 2022-12-06 07:08:43 +00:00
parent 42b8867148
commit 30e235f0a1
9 changed files with 74 additions and 22 deletions

View File

@ -53,7 +53,7 @@ impl MgmtClient {
.method(Method::GET) .method(Method::GET)
.uri(url) .uri(url)
.body(Body::empty())?; .body(Body::empty())?;
return self.send_request(req).await; self.send_request(req).await
} }
/// The HTTP Post method for client /// The HTTP Post method for client
@ -72,7 +72,7 @@ impl MgmtClient {
.uri(url) .uri(url)
.header("content-type", content_type) .header("content-type", content_type)
.body(body)?; .body(body)?;
return self.send_request(req).await; self.send_request(req).await
} }
/// The http PUT method for client /// The http PUT method for client
@ -82,7 +82,7 @@ impl MgmtClient {
.method(Method::PUT) .method(Method::PUT)
.uri(url) .uri(url)
.body(Body::from(data))?; .body(Body::from(data))?;
return self.send_request(req).await; self.send_request(req).await
} }
async fn send_request(&self, req: Request<Body>) -> Result<Response<Body>> { async fn send_request(&self, req: Request<Body>) -> Result<Response<Body>> {

View File

@ -2452,6 +2452,7 @@ dependencies = [
name = "runtimes" name = "runtimes"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"agent",
"anyhow", "anyhow",
"common", "common",
"hyper", "hyper",

View File

@ -116,5 +116,6 @@ impl_agent!(
get_oom_event | crate::Empty | crate::OomEventResponse | Some(0), get_oom_event | crate::Empty | crate::OomEventResponse | Some(0),
get_ip_tables | crate::GetIPTablesRequest | crate::GetIPTablesResponse | None, get_ip_tables | crate::GetIPTablesRequest | crate::GetIPTablesResponse | None,
set_ip_tables | crate::SetIPTablesRequest | crate::SetIPTablesResponse | None, set_ip_tables | crate::SetIPTablesRequest | crate::SetIPTablesResponse | None,
get_volume_stats | crate::VolumeStatsRequest | crate::VolumeStatsResponse | None get_volume_stats | crate::VolumeStatsRequest | crate::VolumeStatsResponse | None,
resize_volume | crate::ResizeVolumeRequest | crate::Empty | None
); );

View File

@ -20,11 +20,12 @@ use crate::{
GetIPTablesResponse, GuestDetailsResponse, HealthCheckResponse, HugetlbStats, IPAddress, GetIPTablesResponse, GuestDetailsResponse, HealthCheckResponse, HugetlbStats, IPAddress,
IPFamily, Interface, Interfaces, KernelModule, MemHotplugByProbeRequest, MemoryData, IPFamily, Interface, Interfaces, KernelModule, MemHotplugByProbeRequest, MemoryData,
MemoryStats, NetworkStats, OnlineCPUMemRequest, PidsStats, ReadStreamRequest, MemoryStats, NetworkStats, OnlineCPUMemRequest, PidsStats, ReadStreamRequest,
ReadStreamResponse, RemoveContainerRequest, ReseedRandomDevRequest, Route, Routes, ReadStreamResponse, RemoveContainerRequest, ReseedRandomDevRequest, ResizeVolumeRequest,
SetGuestDateTimeRequest, SetIPTablesRequest, SetIPTablesResponse, SignalProcessRequest, Route, Routes, SetGuestDateTimeRequest, SetIPTablesRequest, SetIPTablesResponse,
StatsContainerResponse, Storage, StringUser, ThrottlingData, TtyWinResizeRequest, SignalProcessRequest, StatsContainerResponse, Storage, StringUser, ThrottlingData,
UpdateContainerRequest, UpdateInterfaceRequest, UpdateRoutesRequest, VersionCheckResponse, TtyWinResizeRequest, UpdateContainerRequest, UpdateInterfaceRequest, UpdateRoutesRequest,
VolumeStatsRequest, VolumeStatsResponse, WaitProcessRequest, WriteStreamRequest, VersionCheckResponse, VolumeStatsRequest, VolumeStatsResponse, WaitProcessRequest,
WriteStreamRequest,
}, },
OomEventResponse, WaitProcessResponse, WriteStreamResponse, OomEventResponse, WaitProcessResponse, WriteStreamResponse,
}; };
@ -860,10 +861,21 @@ impl From<VolumeStatsRequest> for agent::VolumeStatsRequest {
impl From<csi::VolumeStatsResponse> for VolumeStatsResponse { impl From<csi::VolumeStatsResponse> for VolumeStatsResponse {
fn from(from: csi::VolumeStatsResponse) -> Self { fn from(from: csi::VolumeStatsResponse) -> Self {
let result: String = format!( let result: String = format!(
"Usage: {:?}\nVolume Condition: {:?}", "Usage: {:?} Volume Condition: {:?}",
from.get_usage(), from.get_usage(),
from.get_volume_condition() from.get_volume_condition()
); );
Self { data: result } Self { data: result }
} }
} }
impl From<ResizeVolumeRequest> for agent::ResizeVolumeRequest {
fn from(from: ResizeVolumeRequest) -> Self {
Self {
volume_guest_path: from.volume_guest_path,
size: from.size,
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}

View File

@ -89,4 +89,5 @@ pub trait Agent: AgentManager + HealthService + Send + Sync {
async fn get_ip_tables(&self, req: GetIPTablesRequest) -> Result<GetIPTablesResponse>; async fn get_ip_tables(&self, req: GetIPTablesRequest) -> Result<GetIPTablesResponse>;
async fn set_ip_tables(&self, req: SetIPTablesRequest) -> Result<SetIPTablesResponse>; async fn set_ip_tables(&self, req: SetIPTablesRequest) -> Result<SetIPTablesResponse>;
async fn get_volume_stats(&self, req: VolumeStatsRequest) -> Result<VolumeStatsResponse>; async fn get_volume_stats(&self, req: VolumeStatsRequest) -> Result<VolumeStatsResponse>;
async fn resize_volume(&self, req: ResizeVolumeRequest) -> Result<Empty>;
} }

View File

@ -15,7 +15,9 @@ hyper = { version = "0.14.20", features = ["stream", "server", "http1"] }
hyperlocal = "0.8" hyperlocal = "0.8"
serde_json = "1.0.88" serde_json = "1.0.88"
nix = "0.25.0" nix = "0.25.0"
url = "2.3.1"
agent = { path = "../agent" }
common = { path = "./common" } common = { path = "./common" }
kata-types = { path = "../../../libs/kata-types" } kata-types = { path = "../../../libs/kata-types" }
kata-sys-util = { path = "../../../libs/kata-sys-util" } kata-sys-util = { path = "../../../libs/kata-sys-util" }

View File

@ -27,4 +27,5 @@ pub trait Sandbox: Send + Sync {
async fn set_iptables(&self, is_ipv6: bool, data: Vec<u8>) -> Result<Vec<u8>>; async fn set_iptables(&self, is_ipv6: bool, data: Vec<u8>) -> Result<Vec<u8>>;
async fn get_iptables(&self, is_ipv6: bool) -> Result<Vec<u8>>; async fn get_iptables(&self, is_ipv6: bool) -> Result<Vec<u8>>;
async fn direct_volume_stats(&self, volume_path: &str) -> Result<String>; async fn direct_volume_stats(&self, volume_path: &str) -> Result<String>;
async fn direct_volume_resize(&self, resize_req: agent::ResizeVolumeRequest) -> Result<()>;
} }

View File

@ -7,13 +7,17 @@
// This defines the handlers corresponding to the url when a request is sent to destined url, // This defines the handlers corresponding to the url when a request is sent to destined url,
// the handler function should be invoked, and the corresponding data will be in the response // the handler function should be invoked, and the corresponding data will be in the response
use anyhow::{anyhow, Result}; use agent::ResizeVolumeRequest;
use anyhow::{anyhow, Context, Result};
use common::Sandbox; use common::Sandbox;
use hyper::{Body, Method, Request, Response, StatusCode}; use hyper::{Body, Method, Request, Response, StatusCode};
use std::sync::Arc; use std::sync::Arc;
use url::Url; use url::Url;
use shim_interface::shim_mgmt::{AGENT_URL, IP6_TABLE_URL, IP_TABLE_URL, DIRECT_VOLUMN_PATH_KEY, DIRECT_VOLUMN_STATS_URL,}; use shim_interface::shim_mgmt::{
AGENT_URL, DIRECT_VOLUME_PATH_KEY, DIRECT_VOLUME_RESIZE_URL, DIRECT_VOLUME_STATS_URL,
IP6_TABLE_URL, IP_TABLE_URL,
};
// main router for response, this works as a multiplexer on // main router for response, this works as a multiplexer on
// http arrival which invokes the corresponding handler function // http arrival which invokes the corresponding handler function
@ -35,7 +39,10 @@ pub(crate) async fn handler_mux(
(&Method::PUT, IP6_TABLE_URL) | (&Method::GET, IP6_TABLE_URL) => { (&Method::PUT, IP6_TABLE_URL) | (&Method::GET, IP6_TABLE_URL) => {
ipv6_table_handler(sandbox, req).await ipv6_table_handler(sandbox, req).await
} }
(&Method::POST, DIRECT_VOLUMN_STATS_URL) => direct_volume_stats_handler(sandbox, req).await, (&Method::POST, DIRECT_VOLUME_STATS_URL) => direct_volume_stats_handler(sandbox, req).await,
(&Method::POST, DIRECT_VOLUME_RESIZE_URL) => {
direct_volume_resize_handler(sandbox, req).await
}
_ => Ok(not_found(req).await), _ => Ok(not_found(req).await),
} }
} }
@ -109,18 +116,33 @@ async fn direct_volume_stats_handler(
req: Request<Body>, req: Request<Body>,
) -> Result<Response<Body>> { ) -> Result<Response<Body>> {
let params = Url::parse(&req.uri().to_string()) let params = Url::parse(&req.uri().to_string())
.unwrap() .map_err(|e| anyhow!(e))?
.query_pairs() .query_pairs()
.into_owned() .into_owned()
.collect::<std::collections::HashMap<String, String>>(); .collect::<std::collections::HashMap<String, String>>();
let volume_path = params.get(DIRECT_VOLUMN_PATH_KEY).unwrap(); let volume_path = params
.get(DIRECT_VOLUME_PATH_KEY)
.context("shim-mgmt: volume path key not found in request params")?;
let result = sandbox.direct_volume_stats(volume_path).await; let result = sandbox.direct_volume_stats(volume_path).await;
match result { match result {
Ok(stats) => Ok(Response::new(Body::from(stats))), Ok(stats) => Ok(Response::new(Body::from(stats))),
Err(e) => { _ => Err(anyhow!("handler: Failed to get volume stats")),
let builder = Response::builder().status(StatusCode::INTERNAL_SERVER_ERROR);
let resp = builder.body(Body::from(e.to_string())).unwrap();
Ok(resp)
} }
} }
async fn direct_volume_resize_handler(
sandbox: Arc<dyn Sandbox>,
req: Request<Body>,
) -> Result<Response<Body>> {
let body = hyper::body::to_bytes(req.into_body()).await?;
// unserialize json body into resizeRequest struct
let resize_req: ResizeVolumeRequest =
serde_json::from_slice(&body).context("shim-mgmt: deserialize resizeRequest failed")?;
let result = sandbox.direct_volume_resize(resize_req).await;
match result {
Ok(_) => Ok(Response::new(Body::from(""))),
_ => Err(anyhow!("handler: Failed to resize volume")),
}
} }

View File

@ -334,8 +334,20 @@ impl Sandbox for VirtSandbox {
let req: agent::VolumeStatsRequest = VolumeStatsRequest { let req: agent::VolumeStatsRequest = VolumeStatsRequest {
volume_guest_path: volume_guest_path.to_string(), volume_guest_path: volume_guest_path.to_string(),
}; };
let result = self.agent.get_volume_stats(req).await?.data; let result = self
Ok(result) .agent
.get_volume_stats(req)
.await
.context("sandbox: failed to process direct volume stats query")?;
Ok(result.data)
}
async fn direct_volume_resize(&self, resize_req: agent::ResizeVolumeRequest) -> Result<()> {
self.agent
.resize_volume(resize_req)
.await
.context("sandbox: failed to resize direct-volume")?;
Ok(())
} }
async fn set_iptables(&self, is_ipv6: bool, data: Vec<u8>) -> Result<Vec<u8>> { async fn set_iptables(&self, is_ipv6: bool, data: Vec<u8>) -> Result<Vec<u8>> {