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