agent: Separate the ImageService from the AgentService

Use a separate ImageService to support PullImage.

Fixes #2984

Signed-off-by: wllenyj <wllenyj@linux.alibaba.com>
This commit is contained in:
wllenyj 2021-10-24 03:23:12 +08:00 committed by Samuel Ortiz
parent 23bd6fe5da
commit dfb8c965e6
9 changed files with 295 additions and 121 deletions

View File

@ -13,6 +13,7 @@ fn main() {
"protos/health.proto",
"protos/google/protobuf/empty.proto",
"protos/oci.proto",
"protos/image.proto",
];
Codegen::new()

View File

@ -67,7 +67,6 @@ service AgentService {
rpc CopyFile(CopyFileRequest) returns (google.protobuf.Empty);
rpc GetOOMEvent(GetOOMEventRequest) returns (OOMEvent);
rpc AddSwap(AddSwapRequest) returns (google.protobuf.Empty);
rpc PullImage(PullImageRequest) returns (google.protobuf.Empty);
}
message CreateContainerRequest {
@ -514,9 +513,3 @@ message GetMetricsRequest {}
message Metrics {
string metrics = 1;
}
message PullImageRequest {
string image = 1;
string container_id = 2;
string source_creds = 3;
}

View File

@ -0,0 +1,31 @@
//
// Copyright (c) 2021 Alibaba Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
syntax = "proto3";
option go_package = "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/agent/protocols/grpc";
package grpc;
// Image defines the public APIs for managing images.
service Image {
// PullImage pulls an image with authentication config.
rpc PullImage(PullImageRequest) returns (PullImageResponse) {}
}
message PullImageRequest {
// Image name (e.g. docker.io/library/busybox:latest).
string image = 1;
// Unique image identifier, used to avoid duplication when unpacking the image layers.
string container_id = 2;
// Use USERNAME[:PASSWORD] for accessing the registry
string source_creds = 3;
}
message PullImageResponse {
// Reference to the image in use. For most runtimes, this should be an
// image ID or digest.
string image_ref = 1;
}

View File

@ -10,5 +10,7 @@ pub mod agent_ttrpc;
pub mod empty;
pub mod health;
pub mod health_ttrpc;
pub mod image;
pub mod image_ttrpc;
pub mod oci;
pub mod types;

168
src/agent/src/image_rpc.rs Normal file
View File

@ -0,0 +1,168 @@
// Copyright (c) 2021 Alibaba Cloud
//
// SPDX-License-Identifier: Apache-2.0
//
use std::fs;
use std::path::PathBuf;
use std::process::{Command, ExitStatus};
use std::sync::Arc;
use anyhow::{anyhow, ensure, Result};
use async_trait::async_trait;
use protocols::image;
use tokio::sync::Mutex;
use ttrpc::{self, error::get_rpc_status as ttrpc_error};
use crate::rpc::{verify_cid, CONTAINER_BASE};
use crate::sandbox::Sandbox;
const SKOPEO_PATH: &str = "/usr/bin/skopeo";
const UMOCI_PATH: &str = "/usr/local/bin/umoci";
const IMAGE_OCI: &str = "image_oci:latest";
// Convenience macro to obtain the scope logger
macro_rules! sl {
() => {
slog_scope::logger()
};
}
pub struct ImageService {
sandbox: Arc<Mutex<Sandbox>>,
}
impl ImageService {
pub fn new(sandbox: Arc<Mutex<Sandbox>>) -> Self {
Self { sandbox }
}
fn build_oci_path(cid: &str) -> PathBuf {
let mut oci_path = PathBuf::from("/tmp");
oci_path.push(cid);
oci_path.push(IMAGE_OCI);
oci_path
}
fn pull_image_from_registry(image: &str, cid: &str, source_creds: &Option<&str>) -> Result<()> {
let source_image = format!("{}{}", "docker://", image);
let mut manifest_path = PathBuf::from("/tmp");
manifest_path.push(cid);
manifest_path.push("image_manifest");
let target_path_manifest = format!("dir://{}", manifest_path.to_string_lossy());
// Define the target transport and path for the OCI image, without signature
let oci_path = Self::build_oci_path(cid);
let target_path_oci = format!("oci://{}", oci_path.to_string_lossy());
fs::create_dir_all(&manifest_path)?;
fs::create_dir_all(&oci_path)?;
info!(sl!(), "Attempting to pull image {}...", &source_image);
let mut pull_command = Command::new(SKOPEO_PATH);
pull_command
// TODO: need to create a proper policy
.arg("--insecure-policy")
.arg("copy")
.arg(source_image)
.arg(&target_path_manifest);
if let Some(source_creds) = source_creds {
pull_command.arg("--src-creds").arg(source_creds);
}
let status: ExitStatus = pull_command.status()?;
ensure!(
status.success(),
"failed to copy image manifest: {:?}",
status,
);
// Copy image from one local file-system to another
// Resulting image is still stored in manifest format, but no longer includes the signature
// The image with a signature can then be unpacked into a bundle
let status: ExitStatus = Command::new(SKOPEO_PATH)
.arg("--insecure-policy")
.arg("copy")
.arg(&target_path_manifest)
.arg(&target_path_oci)
.arg("--remove-signatures")
.status()?;
ensure!(status.success(), "failed to copy image oci: {:?}", status);
// To save space delete the manifest.
// TODO LATER - when verify image is added, this will need moving the end of that, if required
fs::remove_dir_all(&manifest_path)?;
Ok(())
}
fn unpack_image(cid: &str) -> Result<()> {
let source_path_oci = Self::build_oci_path(cid);
let target_path_bundle = format!("{}{}{}", CONTAINER_BASE, "/", cid);
info!(sl!(), "unpack image"; "cid" => cid, "target_bundle_path" => &target_path_bundle);
// Unpack image
let status: ExitStatus = Command::new(UMOCI_PATH)
.arg("unpack")
.arg("--image")
.arg(&source_path_oci)
.arg(&target_path_bundle)
.status()?;
ensure!(status.success(), "failed to unpack image: {:?}", status);
// To save space delete the oci image after unpack
fs::remove_dir_all(&source_path_oci)?;
Ok(())
}
async fn pull_image(&self, req: &image::PullImageRequest) -> Result<String> {
let image = req.get_image();
let mut cid = req.get_container_id();
if cid.is_empty() {
let v: Vec<&str> = image.rsplit('/').collect();
if !v[0].is_empty() {
cid = v[0]
} else {
return Err(anyhow!("Invalid image name. {}", image));
}
} else {
verify_cid(cid)?;
}
let source_creds = (!req.get_source_creds().is_empty()).then(|| req.get_source_creds());
Self::pull_image_from_registry(image, cid, &source_creds)?;
Self::unpack_image(cid)?;
let mut sandbox = self.sandbox.lock().await;
sandbox.images.insert(String::from(image), cid.to_string());
Ok(image.to_owned())
}
}
#[async_trait]
impl protocols::image_ttrpc::Image for ImageService {
async fn pull_image(
&self,
_ctx: &ttrpc::r#async::TtrpcContext,
req: image::PullImageRequest,
) -> ttrpc::Result<image::PullImageResponse> {
match self.pull_image(&req).await {
Ok(r) => {
let mut resp = image::PullImageResponse::new();
resp.image_ref = r;
return Ok(resp);
}
Err(e) => {
return Err(ttrpc_error(ttrpc::Code::INTERNAL, e.to_string()));
}
}
}
}

View File

@ -73,6 +73,7 @@ use tokio::{
task::JoinHandle,
};
mod image_rpc;
mod rpc;
mod tracer;

View File

@ -11,7 +11,6 @@ use tokio::sync::Mutex;
use std::ffi::CString;
use std::io;
use std::path::Path;
use std::process::ExitStatus;
use std::sync::Arc;
use ttrpc::{
self,
@ -45,6 +44,7 @@ use nix::unistd::{self, Pid};
use rustjail::process::ProcessOperations;
use crate::device::{add_devices, get_virtio_blk_pci_device_name, update_device_cgroup};
use crate::image_rpc;
use crate::linux_abi::*;
use crate::metrics::get_metrics;
use crate::mount::{add_storages, baremount, remove_mounts, STORAGE_HANDLER_LIST};
@ -77,10 +77,8 @@ use std::io::{BufRead, BufReader};
use std::os::unix::fs::FileExt;
use std::path::PathBuf;
const CONTAINER_BASE: &str = "/run/kata-containers";
pub const CONTAINER_BASE: &str = "/run/kata-containers";
const MODPROBE_PATH: &str = "/sbin/modprobe";
const SKOPEO_PATH: &str = "/usr/bin/skopeo";
const UMOCI_PATH: &str = "/usr/local/bin/umoci";
// Convenience macro to obtain the scope logger
macro_rules! sl {
@ -113,7 +111,7 @@ pub struct AgentService {
//
// ^[a-zA-Z0-9][a-zA-Z0-9_.-]+$
//
fn verify_cid(id: &str) -> Result<()> {
pub fn verify_cid(id: &str) -> Result<()> {
let valid = id.len() > 1
&& id.chars().next().unwrap().is_alphanumeric()
&& id
@ -678,22 +676,6 @@ impl protocols::agent_ttrpc::AgentService for AgentService {
.map_err(|e| ttrpc_error(ttrpc::Code::INTERNAL, e.to_string()))
}
async fn pull_image(
&self,
_ctx: &TtrpcContext,
req: protocols::agent::PullImageRequest,
) -> ttrpc::Result<protocols::empty::Empty> {
let image = req.get_image();
let cid = req.get_container_id();
let source_creds = (!req.get_source_creds().is_empty()).then(|| req.get_source_creds());
pull_image_from_registry(image, cid, &source_creds)
.map_err(|e| ttrpc_error(ttrpc::Code::INTERNAL, e.to_string()))?;
unpack_image(cid).map_err(|e| ttrpc_error(ttrpc::Code::INTERNAL, e.to_string()))?;
Ok(Empty::new())
}
async fn pause_container(
&self,
ctx: &TtrpcContext,
@ -1403,7 +1385,7 @@ fn find_process<'a>(
}
pub fn start(s: Arc<Mutex<Sandbox>>, server_address: &str) -> TtrpcServer {
let agent_service = Box::new(AgentService { sandbox: s })
let agent_service = Box::new(AgentService { sandbox: s.clone() })
as Box<dyn protocols::agent_ttrpc::AgentService + Send + Sync>;
let agent_worker = Arc::new(agent_service);
@ -1412,15 +1394,21 @@ pub fn start(s: Arc<Mutex<Sandbox>>, server_address: &str) -> TtrpcServer {
Box::new(HealthService {}) as Box<dyn protocols::health_ttrpc::Health + Send + Sync>;
let health_worker = Arc::new(health_service);
let aservice = protocols::agent_ttrpc::create_agent_service(agent_worker);
let image_service = Box::new(image_rpc::ImageService::new(s))
as Box<dyn protocols::image_ttrpc::Image + Send + Sync>;
let hservice = protocols::health_ttrpc::create_health(health_worker);
let agent_service = protocols::agent_ttrpc::create_agent_service(agent_worker);
let health_service = protocols::health_ttrpc::create_health(health_worker);
let image_service = protocols::image_ttrpc::create_image(Arc::new(image_service));
let server = TtrpcServer::new()
.bind(server_address)
.unwrap()
.register_service(aservice)
.register_service(hservice);
.register_service(agent_service)
.register_service(health_service)
.register_service(image_service);
info!(sl!(), "ttRPC server started"; "address" => server_address);
@ -1723,86 +1711,6 @@ fn load_kernel_module(module: &protocols::agent::KernelModule) -> Result<()> {
}
}
fn pull_image_from_registry(image: &str, cid: &str, source_creds: &Option<&str>) -> Result<()> {
let source_image = format!("{}{}", "docker://", image);
let manifest_path = format!("/tmp/{}/image_manifest", cid);
let target_path_manifest = format!("dir://{}", manifest_path);
// Define the target transport and path for the OCI image, without signature
let oci_path = format!("/tmp/{}/image_oci:latest", cid);
let target_path_oci = format!("oci://{}", oci_path);
fs::create_dir_all(&manifest_path)?;
fs::create_dir_all(&oci_path)?;
info!(sl!(), "Attempting to pull image {}...", &source_image);
let mut pull_command = Command::new(SKOPEO_PATH);
pull_command
.arg("--insecure-policy")
.arg("copy")
.arg(source_image)
.arg(&target_path_manifest);
if let Some(source_creds) = source_creds {
pull_command.arg("--src-creds").arg(source_creds);
}
let status: ExitStatus = pull_command.status()?;
if !status.success() {
return Err(anyhow!(format!("failed to pull image: {:?}", status)));
}
// Copy image from one local file-system to another
// Resulting image is still stored in manifest format, but no longer includes the signature
// The image with a signature can then be unpacked into a bundle
let status: ExitStatus = Command::new(SKOPEO_PATH)
.arg("--insecure-policy")
.arg("copy")
.arg(&target_path_manifest)
.arg(&target_path_oci)
.arg("--remove-signatures")
.status()?;
if !status.success() {
return Err(anyhow!(format!("failed to copy image: {:?}", status)));
}
// To save space delete the manifest.
// TODO LATER - when verify image is added, this will need moving the end of that, if required
fs::remove_dir_all(&manifest_path)?;
Ok(())
}
fn unpack_image(cid: &str) -> Result<()> {
let source_path_oci = format!("/tmp/{}/image_oci:latest", cid);
let target_path_bundle = format!("{}{}{}", CONTAINER_BASE, "/", cid);
info!(sl!(), "cid is {:?}", cid);
info!(sl!(), "target_path_bundle is {:?}", target_path_bundle);
// Unpack image
let status: ExitStatus = Command::new(UMOCI_PATH)
.arg("--verbose")
.arg("unpack")
.arg("--image")
.arg(&source_path_oci)
.arg(&target_path_bundle)
.status()?;
if !status.success() {
return Err(anyhow!(format!("failed to unpack image: {:?}", status)));
}
// To save space delete the oci image after unpack
fs::remove_dir_all(&source_path_oci)?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;

View File

@ -56,6 +56,7 @@ pub struct Sandbox {
pub event_rx: Arc<Mutex<Receiver<String>>>,
pub event_tx: Option<Sender<String>>,
pub bind_watcher: BindWatcher,
pub images: HashMap<String, String>,
}
impl Sandbox {
@ -88,6 +89,7 @@ impl Sandbox {
event_rx,
event_tx: Some(tx),
bind_watcher: BindWatcher::new(),
images: HashMap::new(),
})
}

View File

@ -14,6 +14,8 @@ use protocols::agent::*;
use protocols::agent_ttrpc::*;
use protocols::health::*;
use protocols::health_ttrpc::*;
use protocols::image::*;
use protocols::image_ttrpc::*;
use slog::{debug, info};
use std::io;
use std::io::Write; // XXX: for flush()
@ -45,6 +47,7 @@ type AgentCmdFp = fn(
ctx: &Context,
client: &AgentServiceClient,
health: &HealthClient,
image: &ImageClient,
options: &mut Options,
args: &str,
) -> Result<()>;
@ -55,6 +58,7 @@ type BuiltinCmdFp = fn(args: &str) -> (Result<()>, bool);
enum ServiceType {
Agent,
Health,
Image,
}
// XXX: Agent command names *MUST* start with an upper-case letter.
@ -260,7 +264,7 @@ static AGENT_CMDS: &'static [AgentCmd] = &[
},
AgentCmd {
name: "PullImage",
st: ServiceType::Agent,
st: ServiceType::Image,
fp: agent_cmd_pull_image,
},
];
@ -316,6 +320,7 @@ fn get_agent_cmd_details() -> Vec<String> {
let service = match cmd.st {
ServiceType::Agent => "agent",
ServiceType::Health => "health",
ServiceType::Image => "image",
};
cmds.push(format!("{} ({} service)", cmd.name, service));
@ -563,6 +568,16 @@ fn kata_service_health(
Ok(HealthClient::new(ttrpc_client))
}
fn kata_service_image(
server_address: String,
hybrid_vsock_port: u64,
hybrid_vsock: bool,
) -> Result<ImageClient> {
let ttrpc_client = create_ttrpc_client(server_address, hybrid_vsock_port, hybrid_vsock)?;
Ok(ImageClient::new(ttrpc_client))
}
fn announce(cfg: &Config) {
info!(sl!(), "announce"; "config" => format!("{:?}", cfg));
}
@ -603,6 +618,11 @@ pub fn client(cfg: &Config, commands: Vec<&str>) -> Result<()> {
cfg.hybrid_vsock_port,
cfg.hybrid_vsock,
)?;
let image = kata_service_image(
cfg.server_address.clone(),
cfg.hybrid_vsock_port,
cfg.hybrid_vsock,
)?;
let mut options = Options::new();
@ -620,7 +640,7 @@ pub fn client(cfg: &Config, commands: Vec<&str>) -> Result<()> {
"server-address" => cfg.server_address.to_string());
if cfg.interactive {
return interactive_client_loop(&cfg, &mut options, &client, &health, &ttrpc_ctx);
return interactive_client_loop(&cfg, &mut options, &client, &health, &image, &ttrpc_ctx);
}
let mut repeat_count = 1;
@ -635,6 +655,7 @@ pub fn client(cfg: &Config, commands: Vec<&str>) -> Result<()> {
&cfg,
&client,
&health,
&image,
&ttrpc_ctx,
repeat_count,
&mut options,
@ -660,6 +681,7 @@ fn handle_cmd(
cfg: &Config,
client: &AgentServiceClient,
health: &HealthClient,
image: &ImageClient,
ctx: &Context,
repeat_count: i64,
options: &mut Options,
@ -706,7 +728,7 @@ fn handle_cmd(
if first.is_lowercase() {
result = handle_builtin_cmd(cmd, &args);
} else {
result = handle_agent_cmd(ctx, client, health, options, cmd, &args);
result = handle_agent_cmd(ctx, client, health, image, options, cmd, &args);
}
if result.0.is_err() {
@ -755,6 +777,7 @@ fn handle_agent_cmd(
ctx: &Context,
client: &AgentServiceClient,
health: &HealthClient,
image: &ImageClient,
options: &mut Options,
cmd: &str,
args: &str,
@ -764,7 +787,7 @@ fn handle_agent_cmd(
Err(e) => return (Err(e), false),
};
let result = f(ctx, client, health, options, &args);
let result = f(ctx, client, health, image, options, &args);
if result.is_err() {
return (result, false);
}
@ -779,6 +802,7 @@ fn interactive_client_loop(
options: &mut Options,
client: &AgentServiceClient,
health: &HealthClient,
image: &ImageClient,
ctx: &Context,
) -> Result<()> {
let result = builtin_cmd_list("");
@ -801,8 +825,16 @@ fn interactive_client_loop(
continue;
}
let (result, shutdown) =
handle_cmd(cfg, client, health, ctx, repeat_count, options, &cmdline);
let (result, shutdown) = handle_cmd(
cfg,
client,
health,
image,
ctx,
repeat_count,
options,
&cmdline,
);
if result.is_err() {
return result;
}
@ -839,6 +871,7 @@ fn agent_cmd_health_check(
ctx: &Context,
_client: &AgentServiceClient,
health: &HealthClient,
_image: &ImageClient,
_options: &mut Options,
_args: &str,
) -> Result<()> {
@ -865,6 +898,7 @@ fn agent_cmd_health_version(
ctx: &Context,
_client: &AgentServiceClient,
health: &HealthClient,
_image: &ImageClient,
_options: &mut Options,
_args: &str,
) -> Result<()> {
@ -892,6 +926,7 @@ fn agent_cmd_sandbox_create(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
options: &mut Options,
args: &str,
) -> Result<()> {
@ -918,6 +953,7 @@ fn agent_cmd_sandbox_destroy(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
_options: &mut Options,
_args: &str,
) -> Result<()> {
@ -941,6 +977,7 @@ fn agent_cmd_container_create(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
options: &mut Options,
args: &str,
) -> Result<()> {
@ -975,6 +1012,7 @@ fn agent_cmd_container_remove(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
options: &mut Options,
args: &str,
) -> Result<()> {
@ -1002,6 +1040,7 @@ fn agent_cmd_container_exec(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
options: &mut Options,
args: &str,
) -> Result<()> {
@ -1048,6 +1087,7 @@ fn agent_cmd_container_stats(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
options: &mut Options,
args: &str,
) -> Result<()> {
@ -1075,6 +1115,7 @@ fn agent_cmd_container_pause(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
options: &mut Options,
args: &str,
) -> Result<()> {
@ -1102,6 +1143,7 @@ fn agent_cmd_container_resume(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
options: &mut Options,
args: &str,
) -> Result<()> {
@ -1129,6 +1171,7 @@ fn agent_cmd_container_start(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
options: &mut Options,
args: &str,
) -> Result<()> {
@ -1156,6 +1199,7 @@ fn agent_cmd_sandbox_get_guest_details(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
_options: &mut Options,
_args: &str,
) -> Result<()> {
@ -1181,6 +1225,7 @@ fn agent_cmd_container_wait_process(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
options: &mut Options,
args: &str,
) -> Result<()> {
@ -1210,6 +1255,7 @@ fn agent_cmd_container_signal_process(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
options: &mut Options,
args: &str,
) -> Result<()> {
@ -1249,6 +1295,7 @@ fn agent_cmd_sandbox_tracing_start(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
_options: &mut Options,
_args: &str,
) -> Result<()> {
@ -1272,6 +1319,7 @@ fn agent_cmd_sandbox_tracing_stop(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
_options: &mut Options,
_args: &str,
) -> Result<()> {
@ -1295,6 +1343,7 @@ fn agent_cmd_sandbox_update_interface(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
_options: &mut Options,
_args: &str,
) -> Result<()> {
@ -1320,6 +1369,7 @@ fn agent_cmd_sandbox_update_routes(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
_options: &mut Options,
_args: &str,
) -> Result<()> {
@ -1346,6 +1396,7 @@ fn agent_cmd_sandbox_list_interfaces(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
_options: &mut Options,
_args: &str,
) -> Result<()> {
@ -1369,6 +1420,7 @@ fn agent_cmd_sandbox_list_routes(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
_options: &mut Options,
_args: &str,
) -> Result<()> {
@ -1392,6 +1444,7 @@ fn agent_cmd_container_tty_win_resize(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
options: &mut Options,
args: &str,
) -> Result<()> {
@ -1440,6 +1493,7 @@ fn agent_cmd_container_close_stdin(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
options: &mut Options,
args: &str,
) -> Result<()> {
@ -1469,6 +1523,7 @@ fn agent_cmd_container_read_stdout(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
options: &mut Options,
args: &str,
) -> Result<()> {
@ -1507,6 +1562,7 @@ fn agent_cmd_container_read_stderr(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
options: &mut Options,
args: &str,
) -> Result<()> {
@ -1545,6 +1601,7 @@ fn agent_cmd_container_write_stdin(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
options: &mut Options,
args: &str,
) -> Result<()> {
@ -1578,6 +1635,7 @@ fn agent_cmd_sandbox_get_metrics(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
_options: &mut Options,
_args: &str,
) -> Result<()> {
@ -1601,6 +1659,7 @@ fn agent_cmd_sandbox_get_oom_event(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
_options: &mut Options,
_args: &str,
) -> Result<()> {
@ -1624,6 +1683,7 @@ fn agent_cmd_sandbox_copy_file(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
options: &mut Options,
args: &str,
) -> Result<()> {
@ -1716,6 +1776,7 @@ fn agent_cmd_sandbox_reseed_random_dev(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
options: &mut Options,
args: &str,
) -> Result<()> {
@ -1744,6 +1805,7 @@ fn agent_cmd_sandbox_online_cpu_mem(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
options: &mut Options,
args: &str,
) -> Result<()> {
@ -1797,6 +1859,7 @@ fn agent_cmd_sandbox_set_guest_date_time(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
options: &mut Options,
args: &str,
) -> Result<()> {
@ -1840,6 +1903,7 @@ fn agent_cmd_sandbox_add_arp_neighbors(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
_options: &mut Options,
_args: &str,
) -> Result<()> {
@ -1866,6 +1930,7 @@ fn agent_cmd_sandbox_update_container(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
options: &mut Options,
args: &str,
) -> Result<()> {
@ -1896,6 +1961,7 @@ fn agent_cmd_sandbox_mem_hotplug_by_probe(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
options: &mut Options,
args: &str,
) -> Result<()> {
@ -1940,8 +2006,9 @@ fn agent_cmd_sandbox_mem_hotplug_by_probe(
fn agent_cmd_pull_image(
ctx: &Context,
client: &AgentServiceClient,
_client: &AgentServiceClient,
_health: &HealthClient,
image_client: &ImageClient,
options: &mut Options,
args: &str,
) -> Result<()> {
@ -1959,7 +2026,7 @@ fn agent_cmd_pull_image(
debug!(sl!(), "sending request"; "request" => format!("{:?}", req));
let reply = client
let reply = image_client
.pull_image(ctx, &req)
.map_err(|e| anyhow!("{:?}", e).context(ERR_API_FAILED))?;
@ -2038,6 +2105,7 @@ fn agent_cmd_sandbox_add_swap(
ctx: &Context,
client: &AgentServiceClient,
_health: &HealthClient,
_image: &ImageClient,
_options: &mut Options,
_args: &str,
) -> Result<()> {