sn_node_manager/cmd/
daemon.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
9use crate::{
10    add_services::{add_daemon, config::AddDaemonServiceOptions},
11    config::{self, is_running_as_root},
12    helpers::{download_and_extract_release, get_bin_version},
13    print_banner, ServiceManager, VerbosityLevel,
14};
15use color_eyre::{eyre::eyre, Result};
16use sn_releases::{ReleaseType, SafeReleaseRepoActions};
17use sn_service_management::{
18    control::{ServiceControl, ServiceController},
19    DaemonService, NodeRegistry,
20};
21use std::{net::Ipv4Addr, path::PathBuf};
22
23pub async fn add(
24    address: Ipv4Addr,
25    env_variables: Option<Vec<(String, String)>>,
26    port: u16,
27    src_path: Option<PathBuf>,
28    url: Option<String>,
29    version: Option<String>,
30    verbosity: VerbosityLevel,
31) -> Result<()> {
32    if !is_running_as_root() {
33        error!("The daemon add command must run as the root user");
34        return Err(eyre!("The add command must run as the root user"));
35    }
36
37    if verbosity != VerbosityLevel::Minimal {
38        print_banner("Add Daemon Service");
39    }
40
41    let service_user = "safe";
42    let service_manager = ServiceController {};
43    debug!("Trying to create service user '{service_user}' for the daemon");
44    service_manager.create_service_user(service_user)?;
45
46    let mut node_registry = NodeRegistry::load(&config::get_node_registry_path()?)?;
47    let release_repo = <dyn SafeReleaseRepoActions>::default_config();
48
49    let (daemon_src_bin_path, version) = if let Some(path) = src_path {
50        let version = get_bin_version(&path)?;
51        (path, version)
52    } else {
53        download_and_extract_release(
54            ReleaseType::SafenodeManagerDaemon,
55            url.clone(),
56            version,
57            &*release_repo,
58            verbosity,
59            None,
60        )
61        .await?
62    };
63
64    info!("Adding daemon service");
65
66    // At the moment we don't have the option to provide a user for running the service. Since
67    // `safenodemand` requires manipulation of services, the user running it must either be root or
68    // have root access. For now we will just use the `root` user. The user option gets ignored on
69    // Windows anyway, so there shouldn't be a cross-platform issue here.
70    add_daemon(
71        AddDaemonServiceOptions {
72            address,
73            env_variables,
74            daemon_install_bin_path: config::get_daemon_install_path(),
75            daemon_src_bin_path,
76            port,
77            user: "root".to_string(),
78            version,
79        },
80        &mut node_registry,
81        &ServiceController {},
82    )?;
83    Ok(())
84}
85
86pub async fn start(verbosity: VerbosityLevel) -> Result<()> {
87    if !is_running_as_root() {
88        error!("The daemon start command must run as the root user");
89        return Err(eyre!("The start command must run as the root user"));
90    }
91
92    let mut node_registry = NodeRegistry::load(&config::get_node_registry_path()?)?;
93    if let Some(daemon) = &mut node_registry.daemon {
94        if verbosity != VerbosityLevel::Minimal {
95            print_banner("Start Daemon Service");
96        }
97        info!("Starting daemon service");
98
99        let service = DaemonService::new(daemon, Box::new(ServiceController {}));
100        let mut service_manager =
101            ServiceManager::new(service, Box::new(ServiceController {}), verbosity);
102        service_manager.start().await?;
103
104        println!(
105            "Endpoint: {}",
106            service_manager
107                .service
108                .service_data
109                .endpoint
110                .map_or("-".to_string(), |e| e.to_string())
111        );
112
113        node_registry.save()?;
114        return Ok(());
115    }
116
117    error!("The daemon service has not been added yet");
118    Err(eyre!("The daemon service has not been added yet"))
119}
120
121pub async fn stop(verbosity: VerbosityLevel) -> Result<()> {
122    if !is_running_as_root() {
123        error!("The daemon stop command must run as the root user");
124        return Err(eyre!("The stop command must run as the root user"));
125    }
126
127    let mut node_registry = NodeRegistry::load(&config::get_node_registry_path()?)?;
128    if let Some(daemon) = &mut node_registry.daemon {
129        if verbosity != VerbosityLevel::Minimal {
130            print_banner("Stop Daemon Service");
131        }
132        info!("Stopping daemon service");
133
134        let service = DaemonService::new(daemon, Box::new(ServiceController {}));
135        let mut service_manager =
136            ServiceManager::new(service, Box::new(ServiceController {}), verbosity);
137        service_manager.stop().await?;
138
139        node_registry.save()?;
140
141        return Ok(());
142    }
143
144    error!("The daemon service has not been added yet");
145    Err(eyre!("The daemon service has not been added yet"))
146}