rusty_ci/buildbot/
worker.rs

1use crate::unwrap;
2use rand::distributions::Alphanumeric;
3use rand::{thread_rng, Rng};
4use rusty_yaml::Yaml;
5use std::fmt::{Display, Error, Formatter};
6use std::process::exit;
7
8/// This struct holds the information that is used to build the worker `buildbot.tac` file
9/// Each worker has:
10/// - a name that is used by the builders to assign work,
11/// - a password that the master uses to access the worker
12/// - a working directory name that the bot will be created in
13/// - the host address of the master bot, the ip
14/// - the port of the master bot
15#[derive(Clone)]
16pub struct Worker {
17    name: String,
18    dir: String,
19    password: String,
20    masterhost: String,
21    masterport: String,
22}
23
24impl Worker {
25    fn new<S: ToString>(name: S, dir: S, password: S, masterhost: S, masterport: S) -> Self {
26        Self {
27            name: name.to_string(),
28            dir: dir.to_string(),
29            password: password.to_string(),
30            masterhost: masterhost.to_string(),
31            masterport: masterport.to_string(),
32        }
33    }
34
35    /// Retrieves the name field of the struct
36    pub fn get_name(&self) -> String {
37        self.name.clone()
38    }
39
40    /// Retrieves the working dir field of the struct
41    pub fn get_dir(&self) -> String {
42        self.dir.clone()
43    }
44
45    /// Retrieves the password field of the struct
46    pub fn get_password(&self) -> String {
47        self.password.clone()
48    }
49}
50
51/// Convert a Yaml section to a Worker
52///
53/// The worker requires that the yaml section has the following subsections:
54/// `masterhost`, `masterport`, `password`, and `basedir`.
55/// Masterhost holds the host address of the master bot,
56/// Masterport hold the host port of the master bot.
57/// Basedir holds the path of the working directory of the bot
58impl From<Yaml> for Worker {
59    fn from(yaml: Yaml) -> Self {
60        let name = yaml.get_name();
61
62        for section in ["master-ip", "working-dir"].iter() {
63            if !yaml.has_section(section) {
64                error!("There was an error creating a worker: The '{}' section is not specified for '{}'", section, name);
65                exit(1);
66            }
67        }
68
69        let password: String = thread_rng().sample_iter(&Alphanumeric).take(30).collect();
70        let basedir = unwrap(&yaml, "working-dir");
71        let masterhost = unwrap(&yaml, "master-ip");
72
73        // Now, instead of getting the master port from the Yaml object, we just use 9989.
74        Self::new(name, basedir, password, masterhost, String::from("9989"))
75    }
76}
77
78/// This is similar to the Display impl for the MasterConfig struct.
79/// This returns the Python `buildbot.tac` file for an individual worker.
80impl Display for Worker {
81    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
82        writeln!(
83            f,
84            r#"import os
85
86from buildbot_worker.bot import Worker
87from twisted.application import service
88
89basedir = '.'
90rotateLength = 10000000
91maxRotatedFiles = 10
92
93# if this is a relocatable tac file, get the directory containing the TAC
94if basedir == '.':
95    import os.path
96    basedir = os.path.abspath(os.path.dirname(__file__))
97
98# note: this line is matched against to check that this is a worker
99# directory; do not edit it.
100application = service.Application('buildbot-worker')
101
102from twisted.python.logfile import LogFile
103from twisted.python.log import ILogObserver, FileLogObserver
104logfile = LogFile.fromFullPath(
105    os.path.join(basedir, "twistd.log"), rotateLength=rotateLength,
106    maxRotatedFiles=maxRotatedFiles)
107application.setComponent(ILogObserver, FileLogObserver(logfile).emit)
108
109buildmaster_host = '{masterhost}'
110port = {masterport}
111workername = '{name}'
112passwd = '{password}'
113keepalive = 600
114umask = None
115maxdelay = 300
116numcpus = None
117allow_shutdown = None
118maxretries = None
119
120s = Worker(buildmaster_host, port, workername, passwd, basedir,
121           keepalive, umask=umask, maxdelay=maxdelay,
122           numcpus=numcpus, allow_shutdown=allow_shutdown,
123           maxRetries=maxretries)
124s.setServiceParent(application)
125
126"#,
127            name = self.name,
128            password = self.password,
129            masterhost = self.masterhost,
130            masterport = self.masterport
131        )
132    }
133}