ockam_command 0.104.0

End-to-end encryption and mutual authentication for distributed applications.
Documentation
use std::fmt::Write;

use clap::Args;
use colorful::Colorful;
use miette::miette;
use tokio::sync::Mutex;
use tokio::try_join;

use ockam::Context;
use ockam_abac::Resource;
use ockam_api::cli_state::StateDirTrait;
use ockam_api::nodes::models::policy::{Expression, PolicyList};
use ockam_api::nodes::BackgroundNode;
use ockam_core::api::Request;

use crate::node::get_node_name;
use crate::output::Output;
use crate::terminal::OckamColor;
use crate::util::{node_rpc, parse_node_name};
use crate::{CommandGlobalOpts, Result};

#[derive(Clone, Debug, Args)]
pub struct ListCommand {
    #[arg(long, display_order = 900, id = "NODE_NAME")]
    at: Option<String>,

    #[arg(short, long)]
    resource: Resource,
}

impl ListCommand {
    pub fn run(self, options: CommandGlobalOpts) {
        node_rpc(rpc, (options, self));
    }
}

async fn rpc(ctx: Context, (opts, cmd): (CommandGlobalOpts, ListCommand)) -> miette::Result<()> {
    run_impl(&ctx, opts, cmd).await
}

async fn run_impl(ctx: &Context, opts: CommandGlobalOpts, cmd: ListCommand) -> miette::Result<()> {
    let resource = cmd.resource;

    let at = get_node_name(&opts.state, &cmd.at);
    let node_name = parse_node_name(&at)?;

    if !opts.state.nodes.get(&node_name)?.is_running() {
        return Err(miette!("The node '{}' is not running", &node_name));
    }

    let node = BackgroundNode::create(ctx, &opts.state, &node_name).await?;
    let is_finished: Mutex<bool> = Mutex::new(false);

    let get_policies = async {
        let req = Request::get(format!("/policy/{resource}"));
        let policies: PolicyList = node.ask(ctx, req).await?;
        Ok(policies)
    };

    let output_messages = vec![format!(
        "Listing Policies on {} for Resource {}...\n",
        node_name
            .to_string()
            .color(OckamColor::PrimaryResource.color()),
        resource
            .to_string()
            .color(OckamColor::PrimaryResource.color())
    )];

    let progress_output = opts
        .terminal
        .progress_output(&output_messages, &is_finished);

    let (policies, _) = try_join!(get_policies, progress_output)?;

    let list = opts.terminal.build_list(
        policies.expressions(),
        &format!("Policies on Node {} for {}", &node_name, resource),
        &format!("No Policies on Node {} for {}", &node_name, resource),
    )?;
    opts.terminal.stdout().plain(list).write_line()?;

    Ok(())
}

impl Output for Expression {
    fn output(&self) -> Result<String> {
        let mut output = String::new();
        writeln!(
            output,
            "Action: {}",
            self.action()
                .to_string()
                .color(OckamColor::PrimaryResource.color())
        )?;
        write!(
            output,
            "Expression: {}",
            self.expr()
                .to_string()
                .color(OckamColor::PrimaryResource.color())
        )?;
        Ok(output)
    }
}