Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(rust): add command to retrieve the identity listening at some endpoint #8829

Merged
merged 2 commits into from
Mar 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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,92 @@
use crate::shared_args::{IdentityOpts, TimeoutArg};
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,

#[command(flatten)]
pub timeout: TimeoutArg,
}

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,
Some(self.timeout.timeout),
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(())
}
}
Loading