Rename the project to Synchronik

This commit is contained in:
R Tyler Croy 2023-03-12 16:26:15 -07:00
parent 3b95ff87ad
commit 8e600ba3b6
12 changed files with 48 additions and 45 deletions

View File

@ -1,14 +1,14 @@
[package] [package]
name = "janky" name = "synchronik"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
[[bin]] [[bin]]
name = "janky-server" name = "synchronik-server"
path = "src/server/main.rs" path = "src/server/main.rs"
[[bin]] [[bin]]
name = "janky-agent" name = "synchronik-agent"
path = "src/agent/main.rs" path = "src/agent/main.rs"
[dependencies] [dependencies]
@ -30,6 +30,7 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1" serde_json = "1"
serde_yaml = "0.9" serde_yaml = "0.9"
sqlx = { version = "~0.6", features = ["chrono", "json", "migrate", "offline", "sqlite", "uuid", "runtime-async-std-rustls"] } sqlx = { version = "~0.6", features = ["chrono", "json", "migrate", "offline", "sqlite", "uuid", "runtime-async-std-rustls"] }
subprocess = "0.2"
tide = "0" tide = "0"
uuid = { version = "1", features = ["v4", "serde"]} uuid = { version = "1", features = ["v4", "serde"]}
url = "2" url = "2"

View File

@ -1,14 +1,15 @@
= Janky CI = Synchronik
Janky is a simple CI system built in Rust. This is performative coding and not Synchronik is a simple task execution system built in Rust. This is
intended to be a production system you can actually use. performative coding and not intended to be a production system you can actually
use.
* Two binaries: * Two binaries:
* `janky-server` * `synchronik-server`
* Listens HTTP * Listens HTTP
* Does web shit * Does web things
* Interacts with agents * Interacts with agents
* `janky-agent`: * `synchronik-agent`:
* Run workloads * Run workloads
* Listen HTTP * Listen HTTP
* executes commands * executes commands

View File

@ -2,11 +2,11 @@
openapi: "3.0.0" openapi: "3.0.0"
info: info:
description: | description: |
Janky API v1 defintion Synchronik API v1 defintion
version: "1.0.0" version: "1.0.0"
title: Janky APIs title: Synchronik APIs
contact: contact:
email: "rtyler+janky@brokenco.de" email: "rtyler+synchronik@brokenco.de"
license: license:
name: "AGPL v3.0" name: "AGPL v3.0"
url: "https://www.gnu.org/licenses/agpl-3.0.en.html" url: "https://www.gnu.org/licenses/agpl-3.0.en.html"
@ -33,7 +33,7 @@ paths:
- in: path - in: path
name: name name: name
required: true required: true
example: 'janky' example: 'synchronik'
schema: schema:
type: string type: string
responses: responses:

View File

@ -1 +1 @@
{"openapi":"3.0.0","info":{"description":"Janky API v1 defintion\n","version":"1.0.0","title":"Janky APIs","contact":{"email":"rtyler+janky@brokenco.de"},"license":{"name":"AGPL v3.0","url":"https://www.gnu.org/licenses/agpl-3.0.en.html"}},"servers":[{"url":"http://localhost:8000","description":"Local dev server"},{"url":"http://localhost:9000","description":"Local dev agent"}],"tags":[{"name":"agent","description":"Agent APIs"},{"name":"server","description":"Server APIs"}],"paths":{"/api/v1/projects/{name}":{"post":{"tags":["server"],"summary":"Trigger execution for this project","description":null,"parameters":[{"in":"path","name":"name","required":true,"example":"janky","schema":{"type":"string"}}],"responses":{"404":{"summary":"No project configured by that name"},"200":{"summary":"Execution has been triggered"}}}},"/api/v1/capabilities":{"get":{"tags":["agent"],"summary":"Retrieve a list of capabilities of this agent","description":null,"responses":{"200":{"description":"Getting capabilities","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CapsResponse"}}}}}}},"/api/v1/execute":{"put":{"tags":["agent"],"summary":"Execute a series of commands on this agent","description":null,"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommandRequest"},"example":{"commands":[{"script":"echo \"Hi\""}]}}}},"responses":{"201":{"description":"Successfully accepted the commands for execution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommandResponse"}}}},"409":{"description":"Returned when the agent is busy with another series of commands"}}}}},"components":{"schemas":{"CapsResponse":{"type":"object","properties":{"caps":{"type":"array","items":{"$ref":"#/components/schemas/Capability"}}}},"Capability":{"type":"object","properties":{"name":{"type":"string"},"path":{"type":"string"},"data":{"type":"object"}}},"Command":{"type":"object","properties":{"script":{"type":"string","description":"A script that can be exec()'d on the agent"}}},"CommandRequest":{"type":"object","properties":{"commands":{"type":"array","items":{"$ref":"#/components/schemas/Command"}}}},"CommandResponse":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid"},"stream":{"description":"URL to streaming WebSockets logs","type":"string","format":"url"},"task":{"description":"URL to the task metadata","type":"string","format":"url"},"log":{"description":"URL to the raw log of the task run","type":"string","format":"url"}}}}}} {"openapi":"3.0.0","info":{"description":"Synchronik API v1 defintion\n","version":"1.0.0","title":"Synchronik APIs","contact":{"email":"rtyler+synchronik@brokenco.de"},"license":{"name":"AGPL v3.0","url":"https://www.gnu.org/licenses/agpl-3.0.en.html"}},"servers":[{"url":"http://localhost:8000","description":"Local dev server"},{"url":"http://localhost:9000","description":"Local dev agent"}],"tags":[{"name":"agent","description":"Agent APIs"},{"name":"server","description":"Server APIs"}],"paths":{"/api/v1/projects/{name}":{"post":{"tags":["server"],"summary":"Trigger execution for this project","description":null,"parameters":[{"in":"path","name":"name","required":true,"example":"synchronik","schema":{"type":"string"}}],"responses":{"404":{"summary":"No project configured by that name"},"200":{"summary":"Execution has been triggered"}}}},"/api/v1/capabilities":{"get":{"tags":["agent"],"summary":"Retrieve a list of capabilities of this agent","description":null,"responses":{"200":{"description":"Getting capabilities","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CapsResponse"}}}}}}},"/api/v1/execute":{"put":{"tags":["agent"],"summary":"Execute a series of commands on this agent","description":null,"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommandRequest"},"example":{"commands":[{"script":"echo \"Hi\""}]}}}},"responses":{"201":{"description":"Successfully accepted the commands for execution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommandResponse"}}}},"409":{"description":"Returned when the agent is busy with another series of commands"}}}}},"components":{"schemas":{"CapsResponse":{"type":"object","properties":{"caps":{"type":"array","items":{"$ref":"#/components/schemas/Capability"}}}},"Capability":{"type":"object","properties":{"name":{"type":"string"},"path":{"type":"string"},"data":{"type":"object"}}},"Command":{"type":"object","properties":{"script":{"type":"string","description":"A script that can be exec()'d on the agent"}}},"CommandRequest":{"type":"object","properties":{"commands":{"type":"array","items":{"$ref":"#/components/schemas/Command"}}}},"CommandResponse":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid"},"stream":{"description":"URL to streaming WebSockets logs","type":"string","format":"url"},"task":{"description":"URL to the task metadata","type":"string","format":"url"},"log":{"description":"URL to the raw log of the task run","type":"string","format":"url"}}}}}}

View File

@ -1,5 +1,5 @@
--- ---
# This is a Janky formatted YAML file. Using YAML for now to make hacking on # This is a Synchronik formatted YAML file. Using YAML for now to make hacking on
# this quicker and easier # this quicker and easier
needs: needs:

View File

@ -5,22 +5,22 @@ agents:
'Duplicate Local': 'Duplicate Local':
url: 'http://localhost:9000' url: 'http://localhost:9000'
projects: projects:
'janky': 'synchronik':
description: | description: |
Self-hosted Janky project Self-hosted project
filename: 'ci.janky.yml' filename: 'ci.synchronik.yml'
scm: scm:
github: github:
owner: 'rtyler' owner: 'rtyler'
repo: 'janky' repo: 'synchronik'
ref: 'main' ref: 'main'
'janky with spaces': 'with spaces':
description: A test configuration with spaces in the name description: A test configuration with spaces in the name
filename: 'ci.janky.yml' filename: 'ci.synchronik.yml'
scm: scm:
github: github:
owner: 'rtyler' owner: 'rtyler'
repo: 'janky' repo: 'synchronik'
ref: 'main' ref: 'main'
# The filetype Git is not yet supported # The filetype Git is not yet supported
#- type: 'git' #- type: 'git'

View File

@ -5,8 +5,8 @@ use std::path::PathBuf;
use async_std::channel::{bounded, Receiver, Sender}; use async_std::channel::{bounded, Receiver, Sender};
use dotenv::dotenv; use dotenv::dotenv;
use janky::CommandRequest;
use log::*; use log::*;
use synchronik::CommandRequest;
use uuid::Uuid; use uuid::Uuid;
const AGENT_LOGS_DIR: &str = "agent-logs"; const AGENT_LOGS_DIR: &str = "agent-logs";
@ -20,13 +20,13 @@ mod routes {
* GET / * GET /
*/ */
pub async fn index(_req: Request<crate::State>) -> Result<Body, tide::Error> { pub async fn index(_req: Request<crate::State>) -> Result<Body, tide::Error> {
Ok("Hello World from the Janky Agent".into()) Ok("Hello World from the Synchronik Agent".into())
} }
pub mod api { pub mod api {
use crate::caps::*; use crate::caps::*;
use crate::*; use crate::*;
use janky::{CommandRequest, CommandResponse}; use synchronik::{CommandRequest, CommandResponse};
use tide::{Body, Request, Response, StatusCode}; use tide::{Body, Request, Response, StatusCode};
use uuid::Uuid; use uuid::Uuid;

View File

@ -6,10 +6,10 @@ use url::Url;
use crate::AppState; use crate::AppState;
/* /*
* Representation of the Janky YAML format * Representation of the Synchronik YAML format
*/ */
#[derive(Clone, Debug, Deserialize)] #[derive(Clone, Debug, Deserialize)]
pub struct JankyYml { pub struct Yml {
pub needs: Vec<String>, pub needs: Vec<String>,
pub commands: Vec<String>, pub commands: Vec<String>,
} }
@ -44,11 +44,11 @@ pub struct Project {
pub struct Agent { pub struct Agent {
pub name: String, pub name: String,
pub url: Url, pub url: Url,
pub capabilities: Vec<janky::Capability>, pub capabilities: Vec<synchronik::Capability>,
} }
impl Agent { impl Agent {
pub fn new(name: String, url: Url, capabilities: Vec<janky::Capability>) -> Self { pub fn new(name: String, url: Url, capabilities: Vec<synchronik::Capability>) -> Self {
Self { Self {
name, name,
url, url,

View File

@ -1,5 +1,5 @@
/* /*
* This is the main Janky entrypoint for the server" * This is the main Synchronik entrypoint for the server
*/ */
#[macro_use] #[macro_use]
@ -93,7 +93,7 @@ async fn main() -> Result<(), tide::Error> {
let database_url = std::env::var("DATABASE_URL").unwrap_or(":memory:".to_string()); let database_url = std::env::var("DATABASE_URL").unwrap_or(":memory:".to_string());
let pool = SqlitePool::connect(&database_url).await?; let pool = SqlitePool::connect(&database_url).await?;
/* If janky-server is running in memory, make sure the database is set up properly */ /* If synchronik-server is running in memory, make sure the database is set up properly */
if database_url == ":memory:" { if database_url == ":memory:" {
sqlx::migrate!().run(&pool).await?; sqlx::migrate!().run(&pool).await?;
} }
@ -118,10 +118,11 @@ async fn main() -> Result<(), tide::Error> {
for (name, agent) in config.agents.iter() { for (name, agent) in config.agents.iter() {
debug!("Requesting capabilities from agent: {:?}", agent); debug!("Requesting capabilities from agent: {:?}", agent);
let response: janky::CapsResponse = reqwest::get(agent.url.join("/api/v1/capabilities")?) let response: synchronik::CapsResponse =
.await? reqwest::get(agent.url.join("/api/v1/capabilities")?)
.json() .await?
.await?; .json()
.await?;
state.agents.push(Agent::new( state.agents.push(Agent::new(
name.to_string(), name.to_string(),
agent.url.clone(), agent.url.clone(),
@ -177,7 +178,7 @@ async fn main() -> Result<(), tide::Error> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use janky::*; use synchronik::*;
#[test] #[test]
fn agent_can_meet_false() { fn agent_can_meet_false() {

View File

@ -46,7 +46,7 @@ pub async fn project(req: Request<AppState<'_>>) -> Result<Body, tide::Error> {
} }
pub mod api { pub mod api {
use crate::config::{JankyYml, Scm}; use crate::config::{Scm, Yml};
use crate::AppState; use crate::AppState;
use log::*; use log::*;
use serde::Deserialize; use serde::Deserialize;
@ -88,18 +88,18 @@ pub mod api {
&project.filename, &project.filename,
) )
.await?; .await?;
let jankyfile: JankyYml = serde_yaml::from_str(&res.text().await?)?; let config_file: Yml = serde_yaml::from_str(&res.text().await?)?;
debug!("text: {:?}", jankyfile); debug!("text: {:?}", config_file);
for agent in &state.agents { for agent in &state.agents {
if agent.can_meet(&jankyfile.needs) { if agent.can_meet(&config_file.needs) {
debug!("agent: {:?} can meet our needs", agent); debug!("agent: {:?} can meet our needs", agent);
let commands: Vec<janky::Command> = jankyfile let commands: Vec<synchronik::Command> = config_file
.commands .commands
.iter() .iter()
.map(|c| janky::Command::with_script(c)) .map(|c| synchronik::Command::with_script(c))
.collect(); .collect();
let commands = janky::CommandRequest { commands }; let commands = synchronik::CommandRequest { commands };
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let _res = client let _res = client
.put( .put(

View File

@ -1,6 +1,6 @@
<nav class="navbar navbar-expand-lg bg-dark" data-bs-theme="dark"> <nav class="navbar navbar-expand-lg bg-dark" data-bs-theme="dark">
<div class="container-fluid"> <div class="container-fluid">
<a class="navbar-brand" href="/">Janky</a> <a class="navbar-brand" href="/">Synchronik</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
</button> </button>

View File

@ -1,7 +1,7 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<title>Janky</title> <title>Synchronik</title>
<link type="text/css" rel="stylesheet" href="/static/bootstrap.min.css"/> <link type="text/css" rel="stylesheet" href="/static/bootstrap.min.css"/>
<script src="/static/bootstrap.bundle.min.js" integrity="sha384-w76AqPfDkMBDXo30jS1Sgez6pr3x5MlQ1ZAGC+nuZB+EYdgRZgiwxhTBTkF7CXvN" crossorigin="anonymous"></script> <script src="/static/bootstrap.bundle.min.js" integrity="sha384-w76AqPfDkMBDXo30jS1Sgez6pr3x5MlQ1ZAGC+nuZB+EYdgRZgiwxhTBTkF7CXvN" crossorigin="anonymous"></script>