functional prototype
update docs and structs, add actual logic, now it actually works
This commit is contained in:
parent
acf4c9e84d
commit
df0cf3b93d
10 changed files with 322 additions and 24 deletions
83
src/data.rs
83
src/data.rs
|
@ -1,6 +1,7 @@
|
|||
//! Data structs. used by gregory and stuff for handling them
|
||||
|
||||
use serde::Deserialize;
|
||||
use std::time;
|
||||
use std::{collections::HashMap, fs, thread};
|
||||
|
||||
/// The config for gregory
|
||||
|
@ -12,57 +13,88 @@ pub(crate) struct Config {
|
|||
/// - 1: Warning
|
||||
/// - 2: Info
|
||||
/// - 3: Debug
|
||||
#[serde(default = "log_level", rename = "log-level")] // the rename lets it use `log-level` instead in the yaml file - this is not an alias, `log_level` in the yaml will *not* work
|
||||
log_level: u8,
|
||||
#[serde(default = "log_level", rename = "log-level")]
|
||||
// the rename lets it use `log-level` instead in the yaml file - this is not an alias, `log_level` in the yaml will *not* work
|
||||
pub(crate) log_level: u8,
|
||||
/// Maximum number of jobs to run simultaneously
|
||||
#[serde(default = "max_jobs", rename = "max-jobs")]
|
||||
max_jobs: u32,
|
||||
pub(crate) max_jobs: u32,
|
||||
/// Maximum number of threads to use
|
||||
#[serde(default = "max_threads", rename = "max-threads")]
|
||||
max_threads: u32,
|
||||
pub(crate) max_threads: u32,
|
||||
#[serde(default = "data", rename = "data-dir")]
|
||||
pub(crate) data_dir: String,
|
||||
/// Holds the packages, including their compilation and packaging
|
||||
///
|
||||
/// Format: `{ "librewolf": Package { compilation, packaging } }`
|
||||
///
|
||||
/// See [`Package`] for details
|
||||
packages: HashMap<String, Package>,
|
||||
pub(crate) packages: HashMap<String, Package>,
|
||||
/// The jobs for updating the repo, organized by distro/repo name
|
||||
#[serde(rename = "update-repo")]
|
||||
update_repo: HashMap<String, Job>,
|
||||
pub(crate) update_repo: HashMap<String, Job>,
|
||||
/// All volumes, organized like this:
|
||||
///
|
||||
/// Format: `{ "librewolf": "./data/librewolf:/librewolf" }` - like Docker/Podman formatting
|
||||
#[serde(default = "volumes")]
|
||||
volumes: HashMap<String, String>,
|
||||
pub(crate) volumes: HashMap<String, String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub(crate) struct Job {
|
||||
/// An ID to identify the job, such as the compilation of a program
|
||||
#[serde(default = "id")]
|
||||
pub(crate) id: String,
|
||||
#[serde(default = "revision")]
|
||||
pub(crate) revision: String,
|
||||
/// How many threads to limit this job to; recommended to set it to the max threads the job will use
|
||||
///
|
||||
/// If `threads` isn't specified, it will fall back to `max_threads` (from [`Config`]); the same behavior applies if `threads` is greater than `max_threads`
|
||||
#[serde(default = "job_threads")]
|
||||
threads: u32,
|
||||
/// The OCi image to run it in
|
||||
pub(crate) threads: u32,
|
||||
/// The OCI image to run it in
|
||||
///
|
||||
/// For example, `docker.io/library/debian:latest`
|
||||
image: String,
|
||||
pub(crate) image: String,
|
||||
/// The commands to run in the job
|
||||
commands: Vec<String>,
|
||||
volumes: Option<Vec<String>>,
|
||||
/// Whether the job should be privileged
|
||||
pub(crate) commands: Vec<String>,
|
||||
/// A list of all volumes given their name - see [`Config`] -> `volumes`
|
||||
pub(crate) volumes: Option<Vec<String>>,
|
||||
/// Whether the job W be privileged
|
||||
///
|
||||
/// Defauolt: false
|
||||
#[serde(default = "privileged")]
|
||||
privileged: bool,
|
||||
pub(crate) privileged: bool,
|
||||
#[serde(default = "shell")]
|
||||
pub(crate) shell: String,
|
||||
}
|
||||
|
||||
/// Holds the data for a certain package's config
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub(crate) struct Package {
|
||||
/// The compilation [`Job`] - optional
|
||||
compilation: Option<Job>,
|
||||
pub(crate) compilation: Option<Job>,
|
||||
/// The packaging [`Job`]s, organized by the distro/repo name
|
||||
packaging: HashMap<String, Job>,
|
||||
pub(crate) packaging: HashMap<String, Job>,
|
||||
}
|
||||
|
||||
/// The exit status and stuff for a [`Job`]
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct JobExitStatus {
|
||||
pub(crate) job: Job,
|
||||
/// The [`Job`] this status is from
|
||||
///
|
||||
/// This is stored as a u16 rather than a u8 so that 65535 can be returned if there is no exit code rather than doing an Option or something, which I fear will probably come back to haunt me, but whatever
|
||||
pub(crate) exit_code: u16,
|
||||
/// Where the log is
|
||||
///
|
||||
/// TEMPORARY
|
||||
/// TODO: Have main() handle logs and writing them to the database, not doing it in run_job()
|
||||
pub(crate) log_path: String,
|
||||
/// How long it took to run the job
|
||||
pub(crate) duration: time::Duration,
|
||||
/// The name of the container this job ran in
|
||||
pub(crate) container_name: String,
|
||||
}
|
||||
|
||||
pub(crate) fn config_from_file(filename: String) -> Config {
|
||||
|
@ -114,3 +146,22 @@ pub(crate) fn job_threads() -> u32 {
|
|||
pub(crate) fn privileged() -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Default (`/bin/sh`) for which shell to use
|
||||
pub(crate) fn shell() -> String {
|
||||
return "/bin/sh".to_string();
|
||||
}
|
||||
|
||||
/// Default id (`-1`)
|
||||
pub(crate) fn id() -> String {
|
||||
return "-1".to_string();
|
||||
}
|
||||
|
||||
/// Default revision (`1`)
|
||||
pub(crate) fn revision() -> String {
|
||||
return "1".to_string();
|
||||
}
|
||||
|
||||
pub(crate) fn data() -> String {
|
||||
return "./data".to_string();
|
||||
}
|
||||
|
|
83
src/main.rs
83
src/main.rs
|
@ -3,7 +3,16 @@ use crate::data::*;
|
|||
use alphanumeric_sort::sort_str_slice;
|
||||
use clap::{CommandFactory, Parser};
|
||||
use clap_complete::aot::{generate, Bash, Elvish, Fish, PowerShell, Zsh};
|
||||
use std::fs;
|
||||
use std::fs::create_dir_all;
|
||||
use std::fs::write;
|
||||
use std::fs::File;
|
||||
use std::io::stdout;
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
use std::time::Instant;
|
||||
use uuid::Uuid;
|
||||
|
||||
mod cli;
|
||||
mod data;
|
||||
|
@ -40,9 +49,75 @@ fn main() {
|
|||
fn run(config_path: String) {
|
||||
let config = config_from_file(config_path);
|
||||
|
||||
println!("{:?}", config);
|
||||
println!("{:#?}", config);
|
||||
|
||||
let mut jobs: Vec<Job> = Vec::new();
|
||||
|
||||
for (_, package) in config.clone().packages {
|
||||
match package.compilation {
|
||||
Some(tmp) => {
|
||||
jobs.push(tmp);
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
for (_, job) in package.packaging {
|
||||
jobs.push(job);
|
||||
}
|
||||
}
|
||||
|
||||
for (_, job) in config.clone().update_repo {
|
||||
jobs.push(job);
|
||||
}
|
||||
|
||||
for job in jobs {
|
||||
println!("{:#?}", run_job(config.clone(), job));
|
||||
}
|
||||
}
|
||||
|
||||
fn run_job(max_threads: u32, job: Job) {
|
||||
|
||||
}
|
||||
fn run_job(conf: Config, job: Job) -> JobExitStatus {
|
||||
// limit threads to max_threads in the config
|
||||
let mut threads: u32 = job.threads;
|
||||
if job.threads > conf.max_threads {
|
||||
threads = conf.max_threads;
|
||||
}
|
||||
|
||||
let container_name: String = format!("gregory-{}-{}-{}", job.id, job.revision, Uuid::now_v7());
|
||||
|
||||
let log_path = &format!("{}/logs/{container_name}.txt", conf.data_dir); // can't select fields in the format!() {} thing, have to do this
|
||||
let log_dir: &Path = Path::new(log_path);
|
||||
create_dir_all(log_dir.parent().unwrap()).unwrap();
|
||||
write(log_path, job.commands.join("\n")).unwrap();
|
||||
|
||||
// set permissions - *unix specific*
|
||||
let mut perms = File::open(log_path)
|
||||
.unwrap()
|
||||
.metadata()
|
||||
.unwrap()
|
||||
.permissions();
|
||||
PermissionsExt::set_mode(&mut perms, 0o755);
|
||||
|
||||
let now = Instant::now();
|
||||
let cmd_args: Vec<String> = vec![
|
||||
"run".to_string(),
|
||||
format!("--name={container_name}"),
|
||||
format!("--cpus={threads}"),
|
||||
format!("--privileged={}", job.privileged),
|
||||
format!("-v={log_path}:/gregory-entrypoint.sh"),
|
||||
format!("--entrypoint=['{}', '/gregory-entrypoint.sh']", &job.shell),
|
||||
job.clone().image
|
||||
];
|
||||
let cmd_output = Command::new("podman").args(cmd_args).output().unwrap();
|
||||
let elapsed = now.elapsed();
|
||||
|
||||
|
||||
println!("{:?}", cmd_output);
|
||||
|
||||
return JobExitStatus {
|
||||
container_name: container_name,
|
||||
duration: elapsed,
|
||||
job: job,
|
||||
exit_code: cmd_output.status.code().ok_or_else(|| 65535).unwrap() as u16,
|
||||
log_path: log_path.clone(),
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue