mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-08-30 14:25:43 +00:00
agent: Add PullImage endpoint
This commit adds the PullImge endpoint to the agent and the agent-ctl command to test it. Fixes: #2509 Signed-off-by: Georgina Kinge <georgina.kinge@ibm.com> Co-authored-by: stevenhorsman <steven@uk.ibm.com>
This commit is contained in:
parent
c9e6efb1e1
commit
af44b7a591
@ -67,6 +67,7 @@ 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 {
|
||||
@ -513,3 +514,8 @@ message GetMetricsRequest {}
|
||||
message Metrics {
|
||||
string metrics = 1;
|
||||
}
|
||||
|
||||
message PullImageRequest {
|
||||
string image = 1;
|
||||
string container_id = 2;
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ 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,
|
||||
@ -78,6 +79,8 @@ use std::path::PathBuf;
|
||||
|
||||
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 {
|
||||
@ -675,6 +678,21 @@ 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();
|
||||
|
||||
pull_image_from_registry(image, cid)
|
||||
.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,
|
||||
@ -1697,6 +1715,76 @@ fn load_kernel_module(module: &protocols::agent::KernelModule) -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
fn pull_image_from_registry(image: &str, cid: &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)?;
|
||||
|
||||
let status: ExitStatus = Command::new(SKOPEO_PATH)
|
||||
.arg("copy")
|
||||
.arg(source_image)
|
||||
.arg(&target_path_manifest)
|
||||
.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("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::*;
|
||||
|
@ -258,6 +258,11 @@ static AGENT_CMDS: &'static [AgentCmd] = &[
|
||||
st: ServiceType::Agent,
|
||||
fp: agent_cmd_container_write_stdin,
|
||||
},
|
||||
AgentCmd {
|
||||
name: "PullImage",
|
||||
st: ServiceType::Agent,
|
||||
fp: agent_cmd_pull_image,
|
||||
},
|
||||
];
|
||||
|
||||
static BUILTIN_CMDS: &'static [BuiltinCmd] = &[
|
||||
@ -1933,6 +1938,35 @@ fn agent_cmd_sandbox_mem_hotplug_by_probe(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn agent_cmd_pull_image(
|
||||
ctx: &Context,
|
||||
client: &AgentServiceClient,
|
||||
_health: &HealthClient,
|
||||
options: &mut Options,
|
||||
args: &str,
|
||||
) -> Result<()> {
|
||||
let mut req = PullImageRequest::default();
|
||||
|
||||
let ctx = clone_context(ctx);
|
||||
|
||||
let image = utils::get_option("image", options, args);
|
||||
let cid = utils::get_option("cid", options, args);
|
||||
|
||||
req.set_image(image);
|
||||
req.set_container_id(cid);
|
||||
|
||||
debug!(sl!(), "sending request"; "request" => format!("{:?}", req));
|
||||
|
||||
let reply = client
|
||||
.pull_image(ctx, &req)
|
||||
.map_err(|e| anyhow!("{:?}", e).context(ERR_API_FAILED))?;
|
||||
|
||||
info!(sl!(), "response received";
|
||||
"response" => format!("{:?}", reply));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn builtin_cmd_repeat(_args: &str) -> (Result<()>, bool) {
|
||||
// XXX: NOP implementation. Due to the way repeat has to work, providing a
|
||||
|
@ -30,7 +30,7 @@ RUN dnf -y update && dnf install -y \
|
||||
m4 \
|
||||
make \
|
||||
pkgconfig \
|
||||
redhat-release \
|
||||
fedora-release-common \
|
||||
sed \
|
||||
systemd \
|
||||
tar \
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
OS_NAME="Fedora"
|
||||
|
||||
OS_VERSION=${OS_VERSION:-30}
|
||||
OS_VERSION=${OS_VERSION:-34}
|
||||
|
||||
MIRROR_LIST="https://mirrors.fedoraproject.org/metalink?repo=fedora-${OS_VERSION}&arch=\$basearch"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user