kratactl/cli/
mod.rs

1pub mod device;
2pub mod host;
3pub mod image;
4pub mod network;
5pub mod zone;
6
7use crate::cli::device::DeviceCommand;
8use crate::cli::host::HostCommand;
9use crate::cli::image::ImageCommand;
10use crate::cli::zone::ZoneCommand;
11use anyhow::{anyhow, Result};
12use clap::Parser;
13use krata::{
14    client::ControlClientProvider,
15    events::EventStream,
16    v1::control::{control_service_client::ControlServiceClient, ResolveZoneIdRequest},
17};
18use network::NetworkCommand;
19use tonic::{transport::Channel, Request};
20
21#[derive(Parser)]
22#[command(version, about = "Control the krata isolation engine")]
23pub struct ControlCommand {
24    #[arg(
25        short,
26        long,
27        help = "The connection URL to the krata isolation engine",
28        default_value = "unix:///var/lib/krata/daemon.socket"
29    )]
30    connection: String,
31
32    #[command(subcommand)]
33    command: ControlCommands,
34}
35
36#[allow(clippy::large_enum_variant)]
37#[derive(Parser)]
38pub enum ControlCommands {
39    Zone(ZoneCommand),
40    Image(ImageCommand),
41    Network(NetworkCommand),
42    Device(DeviceCommand),
43    Host(HostCommand),
44}
45
46impl ControlCommand {
47    pub async fn run(self) -> Result<()> {
48        let client = ControlClientProvider::dial(self.connection.parse()?).await?;
49        let events = EventStream::open(client.clone()).await?;
50        self.command.run(client, events).await
51    }
52}
53
54impl ControlCommands {
55    pub async fn run(
56        self,
57        client: ControlServiceClient<Channel>,
58        events: EventStream,
59    ) -> Result<()> {
60        match self {
61            ControlCommands::Zone(zone) => zone.run(client, events).await,
62
63            ControlCommands::Network(network) => network.run(client, events).await,
64
65            ControlCommands::Image(image) => image.run(client, events).await,
66
67            ControlCommands::Device(device) => device.run(client, events).await,
68
69            ControlCommands::Host(host) => host.run(client, events).await,
70        }
71    }
72}
73
74pub async fn resolve_zone(
75    client: &mut ControlServiceClient<Channel>,
76    name: &str,
77) -> Result<String> {
78    let reply = client
79        .resolve_zone_id(Request::new(ResolveZoneIdRequest {
80            name: name.to_string(),
81        }))
82        .await?
83        .into_inner();
84
85    if !reply.zone_id.is_empty() {
86        Ok(reply.zone_id)
87    } else {
88        Err(anyhow!("unable to resolve zone '{}'", name))
89    }
90}