Skip to content

Commit

Permalink
feat(rust): add command to retrieve the identity listening at some en…
Browse files Browse the repository at this point in the history
…dpoint

add "ockam secure-channel peer-info" command to retrieve the identity listening at some endpoint.
Add hidden option to avoid calling orchestrator controller when generating enrollment ticket.
  • Loading branch information
polvorin committed Feb 28, 2025
1 parent 3e65649 commit c0a5176
Show file tree
Hide file tree
Showing 9 changed files with 130 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -253,10 +253,16 @@ impl InMemoryNode {
ctx: &Context,
project: &Project,
caller_identity_name: Option<String>,
skip_controller_call: bool,
) -> miette::Result<AuthorityNodeClient> {
let client = self
.node_manager
.create_authority_client_with_project(ctx, project, caller_identity_name)
.create_authority_client_with_project(
ctx,
project,
caller_identity_name,
skip_controller_call,
)
.await?;
if let Some(timeout) = self.timeout {
Ok(client
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ impl NodeManager {
.await?
.wait_until_project_is_ready(ctx, project.model())
.await?;

let project = self
.cli_state
.projects()
Expand All @@ -457,6 +458,7 @@ impl NodeManager {
ctx: &Context,
project: &Project,
caller_identity_name: Option<String>,
skip_controller_call: bool,
) -> miette::Result<AuthorityNodeClient> {
let caller_identifier = self
.get_identifier_by_name(caller_identity_name)
Expand All @@ -476,7 +478,18 @@ impl NodeManager {
};

// Make sure that the project is ready otherwise the next call will fail
let project = self.wait_until_project_is_ready(ctx, project).await?;
// Note: the skip_controller_call workaround is because
// 1) There are cases of projects running entirely self-service, and the
// existing code _does_ call orchestrator' controller endpoint.
// 2) The checks done aren't universally valid, there are cases where
// just the authority exists, and we need to call the authority in order
// to bring up the rest of the system. So "project" node doesn't exist
// at that point
let project = if !skip_controller_call {
self.wait_until_project_is_ready(ctx, project).await?
} else {
project.clone()
};

self.make_authority_node_client(
&project
Expand Down
2 changes: 1 addition & 1 deletion implementations/rust/ockam/ockam_app_lib/src/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ impl AppState {
) -> Result<AuthorityNodeClient> {
let node_manager = self.node_manager.read().await;
Ok(node_manager
.create_authority_client_with_project(ctx, project, caller_identity_name)
.create_authority_client_with_project(ctx, project, caller_identity_name, false)
.await?)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ impl Command for EnrollCommand {
.await?
.with_timeout(self.timeout);
let authority_node_client = node
.create_authority_client_with_project(ctx, &project, Some(identity.name()))
.create_authority_client_with_project(ctx, &project, Some(identity.name()), false)
.await?;

// Enroll if applicable
Expand Down
11 changes: 10 additions & 1 deletion implementations/rust/ockam/ockam_command/src/project/ticket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ pub struct TicketCommand {
/// Return the ticket using the legacy encoding format
#[arg(long, hide = true)]
legacy: bool,

/// Don't wait for "project to be ready", that end up calling orchestrator
#[arg(long, hide = true)]
skip_controller_call: bool,
}

#[async_trait]
Expand Down Expand Up @@ -108,7 +112,12 @@ impl Command for TicketCommand {
.await?;

let authority_node_client = node
.create_authority_client_with_project(ctx, &project, Some(identity))
.create_authority_client_with_project(
ctx,
&project,
Some(identity),
cmd.skip_controller_call,
)
.await?;

let attributes = cmd.attributes()?;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ async fn check_authority_node_accessible(
spinner_option: Option<ProgressBar>,
) -> Result<Project> {
let authority_node = node
.create_authority_client_with_project(ctx, &project, None)
.create_authority_client_with_project(ctx, &project, None, false)
.await?;

if let Some(spinner) = spinner_option.as_ref() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ pub(super) async fn create_authority_client(
.get_identity_name_or_default(&identity_opts.identity_name)
.await?;

node.create_authority_client_with_project(ctx, project, Some(identity))
node.create_authority_client_with_project(ctx, project, Some(identity), false)
.await
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ pub(crate) mod listener;
mod create;
mod delete;
mod list;
mod peer_info;
mod show;

pub use create::CreateCommand;
pub use delete::DeleteCommand;
pub use list::ListCommand;
pub use peer_info::PeerInfoCommand;
pub use show::ShowCommand;

use crate::{docs, CommandGlobalOpts};
Expand Down Expand Up @@ -40,6 +42,8 @@ enum SecureChannelSubcommand {
List(ListCommand),
#[command(display_order = 800)]
Show(ShowCommand),
#[command(display_order = 800)]
PeerInfo(PeerInfoCommand),
}

impl SecureChannelCommand {
Expand All @@ -49,6 +53,7 @@ impl SecureChannelCommand {
SecureChannelSubcommand::Delete(c) => c.run(ctx, opts).await,
SecureChannelSubcommand::List(c) => c.run(ctx, opts).await,
SecureChannelSubcommand::Show(c) => c.run(ctx, opts).await,
SecureChannelSubcommand::PeerInfo(c) => c.run(ctx, opts).await,
}
}

Expand All @@ -58,6 +63,7 @@ impl SecureChannelCommand {
SecureChannelSubcommand::Delete(c) => c.name(),
SecureChannelSubcommand::List(c) => c.name(),
SecureChannelSubcommand::Show(c) => c.name(),
SecureChannelSubcommand::PeerInfo(c) => c.name(),
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use crate::shared_args::IdentityOpts;
use crate::{docs, CommandGlobalOpts};
use clap::Args;
use miette::IntoDiagnostic;
use ockam::{identity::Identifier, Context};
use ockam_api::nodes::service::SecureChannelType;
use ockam_api::nodes::InMemoryNode;
use ockam_api::output::Output;
use ockam_multiaddr::MultiAddr;
use serde::Serialize;

const HELP_DETAIL: &str = "";

#[derive(Debug, Clone, Serialize)]
#[rustfmt::skip]
pub struct PeerInfo {
pub identifier: Identifier,
pub change_history: String,
}

impl Output for PeerInfo {
fn item(&self) -> ockam_api::Result<String> {
Ok(format!(
"\n Identifier: {}\n Change History: {}\n",
self.identifier, self.change_history
))
}
}

/// Retrieve Peer Identity
#[derive(Clone, Debug, Args)]
#[command(help_template = docs::after_help(HELP_DETAIL))]
pub struct PeerInfoCommand {
/// Route to a secure channel listener
#[arg(value_name = "ROUTE", long, display_order = 800)]
pub to: MultiAddr,

#[command(flatten)]
identity_opts: IdentityOpts,
}

impl PeerInfoCommand {
pub fn name(&self) -> String {
"secure-channel peer-info".into()
}

pub async fn run(&self, ctx: &Context, opts: CommandGlobalOpts) -> miette::Result<()> {
let identity_name = opts
.state
.get_identity_name_or_default(&self.identity_opts.identity_name)
.await?;

let node_manager =
InMemoryNode::start_node(ctx, &opts.state, &identity_name, None, None, None, None)
.await?;

let secure_channel = node_manager
.create_secure_channel(
ctx,
self.to.clone(),
Some(identity_name),
None,
None,
None,
SecureChannelType::KeyExchangeAndMessages,
)
.await?;

let peer_identifier = secure_channel.their_identifier();

let change_history = node_manager
.secure_channels()
.identities()
.get_change_history(peer_identifier)
.await?;
let peer_info = PeerInfo {
identifier: peer_identifier.to_owned(),
change_history: change_history.export_as_string()?,
};

opts.terminal
.to_stdout()
.plain(peer_info.item()?)
.json(serde_json::to_string(&peer_info).into_diagnostic()?)
.write_line()?;
Ok(())
}
}

0 comments on commit c0a5176

Please sign in to comment.