132 lines
4.4 KiB
Rust
132 lines
4.4 KiB
Rust
/**
|
|
* The routes module contains all the tide routes and the logic to fulfill the responses for each
|
|
* route.
|
|
*
|
|
* Modules are nested for cleaner organization here
|
|
*/
|
|
use log::*;
|
|
use tide::{Body, Request};
|
|
|
|
use crate::models::Project;
|
|
use crate::AppState;
|
|
|
|
/**
|
|
* GET /
|
|
*/
|
|
pub async fn index(req: Request<AppState<'_>>) -> Result<Body, tide::Error> {
|
|
let agents: Vec<String> = req
|
|
.state()
|
|
.agents
|
|
.iter()
|
|
.map(|a| a.render_compact(req.state()))
|
|
.collect();
|
|
let params = json!({
|
|
"page": "home",
|
|
"agents" : agents,
|
|
"config" : req.state().config,
|
|
"projects" : Project::list(&req.state().db).await?,
|
|
});
|
|
|
|
debug!("Rendering home page with: {:?}", params);
|
|
let mut body = req.state().render("index", ¶ms).await?;
|
|
body.set_mime("text/html");
|
|
Ok(body)
|
|
}
|
|
|
|
/**
|
|
* GET /project/:name
|
|
*/
|
|
pub async fn project(req: Request<AppState<'_>>) -> Result<Body, tide::Error> {
|
|
let name: String = req.param("name")?.into();
|
|
let params = json!({
|
|
"name" : name,
|
|
});
|
|
|
|
let mut body = req.state().render("project", ¶ms).await?;
|
|
body.set_mime("text/html");
|
|
Ok(body)
|
|
}
|
|
|
|
pub mod api {
|
|
use crate::config::{Scm, Yml};
|
|
use crate::AppState;
|
|
use log::*;
|
|
use serde::Deserialize;
|
|
use tide::{Request, Response, StatusCode};
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct RedirectedForm {
|
|
next: Option<String>,
|
|
}
|
|
|
|
/**
|
|
* POST /projects/{name}
|
|
*/
|
|
pub async fn execute_project(mut req: Request<AppState<'_>>) -> tide::Result {
|
|
let name: String = req.param("name")?.into();
|
|
let next: RedirectedForm = req.body_form().await?;
|
|
let state = req.state();
|
|
|
|
if !state.config.has_project(&name) {
|
|
debug!("Could not find project named: {}", name);
|
|
return Ok(Response::new(StatusCode::NotFound));
|
|
}
|
|
|
|
if let Some(project) = state.config.projects.get(&name) {
|
|
match &project.scm {
|
|
Scm::Nonexistent => {}
|
|
Scm::GitHub {
|
|
owner,
|
|
repo,
|
|
scm_ref,
|
|
} => {
|
|
let filename = match &project.filename {
|
|
None => "synchronik.yml".to_string(),
|
|
Some(filename) => filename.to_string(),
|
|
};
|
|
debug!("Fetching the file {} from {}/{}", filename, owner, repo);
|
|
let res = octocrab::instance()
|
|
.repos(owner, repo)
|
|
.raw_file(octocrab::params::repos::Commitish(scm_ref.into()), filename)
|
|
.await?;
|
|
let config_file: Yml = serde_yaml::from_str(&res.text().await?)?;
|
|
debug!("text: {:?}", config_file);
|
|
|
|
for agent in &state.agents {
|
|
if agent.can_meet(&config_file.needs) {
|
|
debug!("agent: {:?} can meet our needs", agent);
|
|
let commands: Vec<synchronik::Command> = config_file
|
|
.commands
|
|
.iter()
|
|
.map(|c| synchronik::Command::with_script(c))
|
|
.collect();
|
|
let commands = synchronik::CommandRequest { commands };
|
|
let client = reqwest::Client::new();
|
|
let _res = client
|
|
.put(
|
|
agent
|
|
.url
|
|
.join("/api/v1/execute")
|
|
.expect("Failed to join execute URL"),
|
|
)
|
|
.json(&commands)
|
|
.send()
|
|
.await?;
|
|
|
|
if let Some(red) = &next.next {
|
|
return Ok(tide::Redirect::new(red).into());
|
|
}
|
|
|
|
return Ok(
|
|
json!({ "msg": format!("Executing on {}", &agent.url) }).into()
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return Ok("{}".into());
|
|
}
|
|
Ok(Response::new(StatusCode::InternalServerError))
|
|
}
|
|
}
|