1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

use std::{fmt, time::Duration};

use crate::{
    cluster::Cluster,
    experiments::{Context, Experiment, ExperimentParam},
    instance,
    instance::Instance,
};
use async_trait::async_trait;
use diem_logger::info;
use futures::future::try_join_all;
use std::{
    collections::HashSet,
    fmt::{Error, Formatter},
};
use structopt::StructOpt;
use tokio::time;

#[derive(StructOpt, Debug)]
pub struct RebootClusterParams {}

pub struct RebootCluster {
    instances: Vec<Instance>,
}

impl ExperimentParam for RebootClusterParams {
    type E = RebootCluster;
    fn build(self, cluster: &Cluster) -> Self::E {
        Self::E {
            instances: <&[instance::Instance]>::clone(&cluster.validator_instances()).to_vec(),
        }
    }
}

#[async_trait]
impl Experiment for RebootCluster {
    fn affected_validators(&self) -> HashSet<String> {
        instance::instancelist_to_set(&self.instances)
    }

    async fn run(&mut self, _context: &mut Context<'_>) -> anyhow::Result<()> {
        let futures: Vec<_> = self.instances.iter().map(Instance::stop).collect();
        try_join_all(futures).await?;
        for inst in &self.instances {
            info!("Starting node {}", inst.peer_name());
            inst.start().await?;
            time::sleep(Duration::from_secs(10)).await;
        }
        Ok(())
    }

    fn deadline(&self) -> Duration {
        Duration::from_secs(20 * 60)
    }
}

impl fmt::Display for RebootCluster {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
        write!(f, "Reboot cluster")
    }
}