Skip to content
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
4 changes: 4 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ and then exit immediately.
This avoids interference between a dfx process performing cleanup at shutdown and
a dfx process that is starting.

=== fix: dfx ping no longer creates a default identity

dfx ping now uses the anonymous identity, and no longer requires dfx.json to be present.

== Dependencies

== Replica
Expand Down
4 changes: 3 additions & 1 deletion docs/cli-reference/dfx-ping.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

Use the `dfx ping` command to check connectivity to the IC or a testnet. This command enables you to verify that you can connect to the environment where you want to deploy to.

Note that you can only run this command from within the project directory structure. For example, if your project name is `hello_world`, your current working directory must be the `hello_world` top-level project directory or one of its subdirectories.
To ping your local server, please note that you can only run this command from within the project directory structure. For example, if your project name is `hello_world`, your current working directory must be the `hello_world` top-level project directory or one of its subdirectories.

To ping mainnet, you can run `dfx ping ic` from any directory.

## Basic usage

Expand Down
15 changes: 12 additions & 3 deletions e2e/tests-dfx/identity.bash
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,21 @@ teardown() {
assert_eq '(false)'
}

@test "dfx ping creates the default identity on first run" {
install_asset identity
@test "dfx ping does not create a default identity" {
dfx_start

assert_file_not_exists "$DFX_CONFIG_ROOT/.config/dfx/identity.json"
assert_file_not_exists "$DFX_CONFIG_ROOT/.config/dfx/identity/default/identity.pem"

assert_command dfx ping

assert_file_not_exists "$DFX_CONFIG_ROOT/.config/dfx/identity.json"
assert_file_not_exists "$DFX_CONFIG_ROOT/.config/dfx/identity/default/identity.pem"

# shellcheck disable=SC2154
assert_match 'Creating the "default" identity.' "$stderr"
assert_not_match 'Creating' "$stderr"
# shellcheck disable=SC2154
assert_not_match 'default' "$stderr"
# shellcheck disable=SC2154
assert_match "ic_api_version" "$stdout"
}
Expand Down
13 changes: 13 additions & 0 deletions e2e/tests-dfx/ping.bash
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,19 @@ teardown() {
assert_match "\"ic_api_version\""
}

@test "dfx ping does not require dfx.json" {
dfx_start
webserver_port=$(cat .dfx/webserver-port)

mkdir "$DFX_E2E_TEMP_DIR/not-a-project"
(
cd "$DFX_E2E_TEMP_DIR/not-a-project"

assert_command dfx ping http://127.0.0.1:"$webserver_port"
assert_match "\"ic_api_version\""
)
}

@test "dfx ping succeeds by network name" {
dfx_start
assert_command dfx ping local
Expand Down
6 changes: 1 addition & 5 deletions e2e/utils/_.bash
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,7 @@ dfx_start() {

wait_until_replica_healthy() {
echo "waiting for replica to become healthy"
(
# dfx ping has side effects, like creating a default identity.
DFX_CONFIG_ROOT="$DFX_E2E_TEMP_DIR/dfx-ping-tmp"
dfx ping --wait-healthy
)
dfx ping --wait-healthy
echo "replica became healthy"
}

Expand Down
31 changes: 11 additions & 20 deletions src/dfx/src/commands/ping.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::config::dfinity::NetworkType;
use crate::lib::environment::{AgentEnvironment, Environment};
use crate::lib::environment::{create_agent, Environment};
use crate::lib::error::{DfxError, DfxResult};
use crate::lib::network::network_descriptor::NetworkDescriptor;
use crate::lib::identity::Identity;
use crate::lib::provider::{
command_line_provider_to_url, get_network_context, get_network_descriptor,
};
Expand All @@ -28,32 +27,24 @@ pub struct PingOpts {
}

pub fn exec(env: &dyn Environment, opts: PingOpts) -> DfxResult {
env.get_config_or_anyhow()?;

// For ping, "provider" could either be a URL or a network name.
// If not passed, we default to the "local" network.
let network_descriptor =
get_network_descriptor(env, opts.network).or_else::<DfxError, _>(|err| {
let agent_url = get_network_descriptor(env, opts.network)
.and_then(|network_descriptor| {
let url = network_descriptor.first_provider()?.to_string();
Ok(url)
})
.or_else::<DfxError, _>(|err| {
let logger = env.get_logger();
warn!(logger, "{}", err);
let network_name = get_network_context()?;
let url = command_line_provider_to_url(&network_name)?;
let is_ic = NetworkDescriptor::is_ic(&network_name, &vec![url.to_string()]);
let network_descriptor = NetworkDescriptor {
name: "-ping-".to_string(),
providers: vec![url],
r#type: NetworkType::Ephemeral,
is_ic,
};
Ok(network_descriptor)
Ok(url)
})?;

let timeout = expiry_duration();
let env = AgentEnvironment::new(env, network_descriptor, timeout)?;

let agent = env
.get_agent()
.ok_or_else(|| anyhow!("Cannot find dfx configuration file in the current working directory. Did you forget to create one?"))?;
let identity = Box::new(Identity::anonymous());
let agent = create_agent(env.get_logger().clone(), &agent_url, identity, timeout)?;

let runtime = Runtime::new().expect("Unable to create a runtime");
if opts.wait_healthy {
Expand Down
40 changes: 16 additions & 24 deletions src/dfx/src/lib/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,19 +232,14 @@ impl<'a> AgentEnvironment<'a> {
network_descriptor: NetworkDescriptor,
timeout: Duration,
) -> DfxResult<Self> {
let logger = backend.get_logger().clone();
let mut identity_manager = IdentityManager::new(backend)?;
let identity = identity_manager.instantiate_selected_identity()?;
let url = network_descriptor.first_provider()?;

let agent_url = network_descriptor.providers.first().with_context(|| {
format!(
"Network '{}' does not specify any network providers.",
network_descriptor.name
)
})?;
Ok(AgentEnvironment {
backend,
agent: create_agent(backend.get_logger().clone(), agent_url, identity, timeout)
.expect("Failed to construct agent."),
agent: create_agent(logger, url, identity, timeout)?,
network_descriptor: network_descriptor.clone(),
identity_manager,
})
Expand Down Expand Up @@ -466,26 +461,23 @@ impl ic_agent::agent::http_transport::PasswordManager for AgentClient {
}
}

fn create_agent(
#[context("Failed to create agent with url {}.", url)]
pub fn create_agent(
logger: Logger,
url: &str,
identity: Box<dyn Identity + Send + Sync>,
timeout: Duration,
) -> Option<Agent> {
AgentClient::new(logger, url.to_string())
.ok()
.and_then(|executor| {
Agent::builder()
.with_transport(
ic_agent::agent::http_transport::ReqwestHttpReplicaV2Transport::create(url)
.unwrap()
.with_password_manager(executor),
)
.with_boxed_identity(identity)
.with_ingress_expiry(Some(timeout))
.build()
.ok()
})
) -> DfxResult<Agent> {
let executor = AgentClient::new(logger, url.to_string())?;
let agent = Agent::builder()
.with_transport(
ic_agent::agent::http_transport::ReqwestHttpReplicaV2Transport::create(url)?
.with_password_manager(executor),
)
.with_boxed_identity(identity)
.with_ingress_expiry(Some(timeout))
.build()?;
Ok(agent)
}

#[cfg(test)]
Expand Down
14 changes: 14 additions & 0 deletions src/dfx/src/lib/network/network_descriptor.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use crate::config::dfinity::NetworkType;
use crate::config::dfinity::{DEFAULT_IC_GATEWAY, DEFAULT_IC_GATEWAY_TRAILING_SLASH};
use crate::lib::error::DfxResult;

use anyhow::bail;

#[derive(Clone, Debug)]
pub struct NetworkDescriptor {
Expand All @@ -26,6 +29,17 @@ impl NetworkDescriptor {
};
name_match || provider_match
}

/// Return the first provider in the list
pub fn first_provider(&self) -> DfxResult<&str> {
match self.providers.first() {
Some(provider) => Ok(provider),
None => bail!(
"Network '{}' does not specify any network providers.",
self.name
),
}
}
}

#[cfg(test)]
Expand Down