mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-09-03 18:04:16 +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:
committed by
stevenhorsman
parent
c9e6efb1e1
commit
af44b7a591
@@ -67,6 +67,7 @@ service AgentService {
|
|||||||
rpc CopyFile(CopyFileRequest) returns (google.protobuf.Empty);
|
rpc CopyFile(CopyFileRequest) returns (google.protobuf.Empty);
|
||||||
rpc GetOOMEvent(GetOOMEventRequest) returns (OOMEvent);
|
rpc GetOOMEvent(GetOOMEventRequest) returns (OOMEvent);
|
||||||
rpc AddSwap(AddSwapRequest) returns (google.protobuf.Empty);
|
rpc AddSwap(AddSwapRequest) returns (google.protobuf.Empty);
|
||||||
|
rpc PullImage(PullImageRequest) returns (google.protobuf.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
message CreateContainerRequest {
|
message CreateContainerRequest {
|
||||||
@@ -513,3 +514,8 @@ message GetMetricsRequest {}
|
|||||||
message Metrics {
|
message Metrics {
|
||||||
string metrics = 1;
|
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::ffi::CString;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::process::ExitStatus;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use ttrpc::{
|
use ttrpc::{
|
||||||
self,
|
self,
|
||||||
@@ -78,6 +79,8 @@ use std::path::PathBuf;
|
|||||||
|
|
||||||
const CONTAINER_BASE: &str = "/run/kata-containers";
|
const CONTAINER_BASE: &str = "/run/kata-containers";
|
||||||
const MODPROBE_PATH: &str = "/sbin/modprobe";
|
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
|
// Convenience macro to obtain the scope logger
|
||||||
macro_rules! sl {
|
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()))
|
.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(
|
async fn pause_container(
|
||||||
&self,
|
&self,
|
||||||
ctx: &TtrpcContext,
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@@ -258,6 +258,11 @@ static AGENT_CMDS: &'static [AgentCmd] = &[
|
|||||||
st: ServiceType::Agent,
|
st: ServiceType::Agent,
|
||||||
fp: agent_cmd_container_write_stdin,
|
fp: agent_cmd_container_write_stdin,
|
||||||
},
|
},
|
||||||
|
AgentCmd {
|
||||||
|
name: "PullImage",
|
||||||
|
st: ServiceType::Agent,
|
||||||
|
fp: agent_cmd_pull_image,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
static BUILTIN_CMDS: &'static [BuiltinCmd] = &[
|
static BUILTIN_CMDS: &'static [BuiltinCmd] = &[
|
||||||
@@ -1933,6 +1938,35 @@ fn agent_cmd_sandbox_mem_hotplug_by_probe(
|
|||||||
Ok(())
|
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]
|
#[inline]
|
||||||
fn builtin_cmd_repeat(_args: &str) -> (Result<()>, bool) {
|
fn builtin_cmd_repeat(_args: &str) -> (Result<()>, bool) {
|
||||||
// XXX: NOP implementation. Due to the way repeat has to work, providing a
|
// 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 \
|
m4 \
|
||||||
make \
|
make \
|
||||||
pkgconfig \
|
pkgconfig \
|
||||||
redhat-release \
|
fedora-release-common \
|
||||||
sed \
|
sed \
|
||||||
systemd \
|
systemd \
|
||||||
tar \
|
tar \
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
OS_NAME="Fedora"
|
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"
|
MIRROR_LIST="https://mirrors.fedoraproject.org/metalink?repo=fedora-${OS_VERSION}&arch=\$basearch"
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user