sn_node_manager/cmd/
local.rs

1// Copyright (C) 2024 MaidSafe.net limited.
2//
3// This SAFE Network Software is licensed to you under The General Public License (GPL), version 3.
4// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed
5// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
6// KIND, either express or implied. Please review the Licences for the specific language governing
7// permissions and limitations relating to use of the SAFE Network Software.
8
9#![allow(clippy::too_many_arguments)]
10
11use super::get_bin_path;
12use crate::{
13    add_services::config::PortRange,
14    local::{kill_network, run_network, LocalNetworkOptions},
15    print_banner, status_report, VerbosityLevel,
16};
17use color_eyre::{eyre::eyre, Help, Report, Result};
18use sn_evm::{EvmNetwork, RewardsAddress};
19use sn_logging::LogFormat;
20use sn_peers_acquisition::PeersArgs;
21use sn_releases::{ReleaseType, SafeReleaseRepoActions};
22use sn_service_management::{
23    control::ServiceController, get_local_node_registry_path, NodeRegistry,
24};
25use std::path::PathBuf;
26
27pub async fn join(
28    build: bool,
29    count: u16,
30    enable_metrics_server: bool,
31    _faucet_path: Option<PathBuf>,
32    _faucet_version: Option<String>,
33    interval: u64,
34    metrics_port: Option<PortRange>,
35    node_path: Option<PathBuf>,
36    node_port: Option<PortRange>,
37    node_version: Option<String>,
38    log_format: Option<LogFormat>,
39    owner: Option<String>,
40    owner_prefix: Option<String>,
41    peers_args: PeersArgs,
42    rpc_port: Option<PortRange>,
43    rewards_address: RewardsAddress,
44    evm_network: Option<EvmNetwork>,
45    skip_validation: bool,
46    verbosity: VerbosityLevel,
47) -> Result<(), Report> {
48    if verbosity != VerbosityLevel::Minimal {
49        print_banner("Joining Local Network");
50    }
51    info!("Joining local network");
52
53    if (enable_metrics_server || metrics_port.is_some()) && !cfg!(feature = "open-metrics") && build
54    {
55        return Err(eyre!(
56        "Metrics server is not available. Please enable the open-metrics feature flag. Run the command with the --features open-metrics"
57    ));
58    }
59
60    let local_node_reg_path = &get_local_node_registry_path()?;
61    let mut local_node_registry = NodeRegistry::load(local_node_reg_path)?;
62
63    let release_repo = <dyn SafeReleaseRepoActions>::default_config();
64
65    #[cfg(feature = "faucet")]
66    let faucet_bin_path = get_bin_path(
67        build,
68        _faucet_path,
69        ReleaseType::Faucet,
70        _faucet_version,
71        &*release_repo,
72        verbosity,
73    )
74    .await?;
75
76    let safenode_bin_path = get_bin_path(
77        build,
78        node_path,
79        ReleaseType::Safenode,
80        node_version,
81        &*release_repo,
82        verbosity,
83    )
84    .await?;
85
86    // If no peers are obtained we will attempt to join the existing local network, if one
87    // is running.
88    let peers = match peers_args.get_peers().await {
89        Ok(peers) => Some(peers),
90        Err(err) => match err {
91            sn_peers_acquisition::error::Error::PeersNotObtained => {
92                warn!("PeersNotObtained, peers is set to None");
93                None
94            }
95            _ => {
96                error!("Failed to obtain peers: {err:?}");
97                return Err(err.into());
98            }
99        },
100    };
101    let options = LocalNetworkOptions {
102        enable_metrics_server,
103        #[cfg(feature = "faucet")]
104        faucet_bin_path,
105        interval,
106        join: true,
107        metrics_port,
108        node_count: count,
109        node_port,
110        owner,
111        owner_prefix,
112        peers,
113        rpc_port,
114        safenode_bin_path,
115        skip_validation,
116        log_format,
117        rewards_address,
118        evm_network,
119    };
120    run_network(options, &mut local_node_registry, &ServiceController {}).await?;
121    Ok(())
122}
123
124pub fn kill(keep_directories: bool, verbosity: VerbosityLevel) -> Result<()> {
125    let local_reg_path = &get_local_node_registry_path()?;
126    let local_node_registry = NodeRegistry::load(local_reg_path)?;
127    if local_node_registry.nodes.is_empty() {
128        info!("No local network is currently running, cannot kill it");
129        println!("No local network is currently running");
130    } else {
131        if verbosity != VerbosityLevel::Minimal {
132            print_banner("Killing Local Network");
133        }
134        info!("Kill local network");
135        kill_network(&local_node_registry, keep_directories)?;
136        std::fs::remove_file(local_reg_path)?;
137    }
138    Ok(())
139}
140
141pub async fn run(
142    build: bool,
143    clean: bool,
144    count: u16,
145    enable_metrics_server: bool,
146    _faucet_path: Option<PathBuf>,
147    _faucet_version: Option<String>,
148    interval: u64,
149    metrics_port: Option<PortRange>,
150    node_path: Option<PathBuf>,
151    node_port: Option<PortRange>,
152    node_version: Option<String>,
153    log_format: Option<LogFormat>,
154    owner: Option<String>,
155    owner_prefix: Option<String>,
156    rpc_port: Option<PortRange>,
157    rewards_address: RewardsAddress,
158    evm_network: Option<EvmNetwork>,
159    skip_validation: bool,
160    verbosity: VerbosityLevel,
161) -> Result<(), Report> {
162    if (enable_metrics_server || metrics_port.is_some()) && !cfg!(feature = "open-metrics") && build
163    {
164        return Err(eyre!(
165        "Metrics server is not available. Please enable the open-metrics feature flag. Run the command with the --features open-metrics"
166    ));
167    }
168
169    // In the clean case, the node registry must be loaded *after* the existing network has
170    // been killed, which clears it out.
171    let local_node_reg_path = &get_local_node_registry_path()?;
172    let mut local_node_registry: NodeRegistry = if clean {
173        debug!(
174            "Clean set to true, removing client, node dir, local registry and killing the network."
175        );
176        let client_data_path = dirs_next::data_dir()
177            .ok_or_else(|| eyre!("Could not obtain user's data directory"))?
178            .join("safe")
179            .join("client");
180        if client_data_path.is_dir() {
181            std::fs::remove_dir_all(client_data_path)?;
182        }
183        if local_node_reg_path.exists() {
184            std::fs::remove_file(local_node_reg_path)?;
185        }
186        kill(false, verbosity)?;
187        NodeRegistry::load(local_node_reg_path)?
188    } else {
189        let local_node_registry = NodeRegistry::load(local_node_reg_path)?;
190        if !local_node_registry.nodes.is_empty() {
191            error!("A local network is already running, cannot run a new one");
192            return Err(eyre!("A local network is already running")
193                .suggestion("Use the kill command to destroy the network then try again"));
194        }
195        local_node_registry
196    };
197
198    if verbosity != VerbosityLevel::Minimal {
199        print_banner("Launching Local Network");
200    }
201    info!("Launching local network");
202
203    let release_repo = <dyn SafeReleaseRepoActions>::default_config();
204
205    #[cfg(feature = "faucet")]
206    let faucet_bin_path = get_bin_path(
207        build,
208        _faucet_path,
209        ReleaseType::Faucet,
210        _faucet_version,
211        &*release_repo,
212        verbosity,
213    )
214    .await?;
215
216    let safenode_bin_path = get_bin_path(
217        build,
218        node_path,
219        ReleaseType::Safenode,
220        node_version,
221        &*release_repo,
222        verbosity,
223    )
224    .await?;
225
226    let options = LocalNetworkOptions {
227        enable_metrics_server,
228        #[cfg(feature = "faucet")]
229        faucet_bin_path,
230        join: false,
231        interval,
232        metrics_port,
233        node_port,
234        node_count: count,
235        owner,
236        owner_prefix,
237        peers: None,
238        rpc_port,
239        safenode_bin_path,
240        skip_validation,
241        log_format,
242        rewards_address,
243        evm_network,
244    };
245    run_network(options, &mut local_node_registry, &ServiceController {}).await?;
246
247    local_node_registry.save()?;
248    Ok(())
249}
250
251pub async fn status(details: bool, fail: bool, json: bool) -> Result<()> {
252    let mut local_node_registry = NodeRegistry::load(&get_local_node_registry_path()?)?;
253    if !json {
254        print_banner("Local Network");
255    }
256    status_report(
257        &mut local_node_registry,
258        &ServiceController {},
259        details,
260        json,
261        fail,
262        true,
263    )
264    .await?;
265    local_node_registry.save()?;
266    Ok(())
267}