feat: status check worker
This introduces a standalone status check ecosystem which does not rely on the VCS. This way, we can implement richer CI mechanisms using our own status checks. On the long term, this means that GitHub will become a second class citizen in this codebase and this is intended. Signed-off-by: Raito Bezarius <masterancpp@gmail.com>
This commit is contained in:
parent
855bde2a4c
commit
c922e6e455
79
ofborg/src/bin/statcheck-worker.rs
Normal file
79
ofborg/src/bin/statcheck-worker.rs
Normal file
|
@ -0,0 +1,79 @@
|
|||
/// Statuses and checks worker
|
||||
/// - will keep a database of changes
|
||||
/// - their statuses
|
||||
/// - their checks
|
||||
/// - is VCS/CI agnostic
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
|
||||
use async_std::task;
|
||||
use ofborg::config;
|
||||
use ofborg::easyamqp;
|
||||
use ofborg::easyamqp::ChannelExt;
|
||||
use ofborg::easyamqp::ConsumerExt;
|
||||
use ofborg::easylapin;
|
||||
use ofborg::tasks;
|
||||
use tracing::info;
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
ofborg::setup_log();
|
||||
|
||||
let arg = env::args()
|
||||
.nth(1)
|
||||
.expect("usage: statcheck-worker <config>");
|
||||
let cfg = config::load(arg.as_ref());
|
||||
|
||||
let conn = easylapin::from_config(&cfg.rabbitmq)?;
|
||||
let mut chan = task::block_on(conn.create_channel())?;
|
||||
|
||||
// an RPC queue for verbs
|
||||
let api_queue_name = "statcheck-api".to_owned();
|
||||
// an event queue to be notified about statuses & checks changes.
|
||||
let event_queue_name = "statcheck-events".to_owned();
|
||||
|
||||
chan.declare_exchange(easyamqp::ExchangeConfig {
|
||||
exchange: api_queue_name.clone(),
|
||||
exchange_type: easyamqp::ExchangeType::Topic,
|
||||
passive: false,
|
||||
durable: true,
|
||||
auto_delete: false,
|
||||
no_wait: false,
|
||||
internal: false,
|
||||
})?;
|
||||
|
||||
chan.declare_queue(easyamqp::QueueConfig {
|
||||
queue: api_queue_name.clone(),
|
||||
passive: false,
|
||||
durable: true,
|
||||
exclusive: false,
|
||||
auto_delete: false,
|
||||
no_wait: false,
|
||||
})?;
|
||||
|
||||
chan.bind_queue(easyamqp::BindQueueConfig {
|
||||
queue: api_queue_name.clone(),
|
||||
exchange: api_queue_name.clone(),
|
||||
routing_key: None,
|
||||
no_wait: false,
|
||||
})?;
|
||||
|
||||
let handle = easylapin::WorkerChannel(chan).consume(
|
||||
tasks::status_check_collector::StatusCheckCollector::new(cfg.statcheck.clone().db),
|
||||
easyamqp::ConsumeConfig {
|
||||
queue: api_queue_name.clone(),
|
||||
consumer_tag: format!("{}-{}", cfg.whoami(), api_queue_name),
|
||||
no_local: false,
|
||||
no_ack: false,
|
||||
no_wait: false,
|
||||
exclusive: false,
|
||||
},
|
||||
)?;
|
||||
|
||||
info!("Waiting for API calls on {}", api_queue_name);
|
||||
info!("Notifying of new changes on {}", event_queue_name);
|
||||
task::block_on(handle);
|
||||
|
||||
drop(conn); // Close connection.
|
||||
info!("Closed the session... EOF");
|
||||
Ok(())
|
||||
}
|
|
@ -26,6 +26,7 @@ pub struct Config {
|
|||
pub nix: NixConfig,
|
||||
pub rabbitmq: RabbitMqConfig,
|
||||
pub vcs: VCSConfig,
|
||||
pub statcheck: StatusCheckConfig,
|
||||
pub pastebin: PastebinConfig,
|
||||
pub log_storage: Option<LogStorage>,
|
||||
|
||||
|
@ -42,6 +43,12 @@ pub struct FeedbackConfig {
|
|||
pub full_logs: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct StatusCheckConfig {
|
||||
#[serde(deserialize_with = "deserialize_and_expand_pathbuf")]
|
||||
pub db: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct PastebinConfig {
|
||||
#[serde(deserialize_with = "deserialize_and_expand_pathbuf")]
|
||||
|
|
|
@ -7,3 +7,4 @@ pub mod githubcommentposter;
|
|||
pub mod log_message_collector;
|
||||
pub mod pastebin_collector;
|
||||
pub mod statscollector;
|
||||
pub mod status_check_collector;
|
||||
|
|
52
ofborg/src/tasks/status_check_collector.rs
Normal file
52
ofborg/src/tasks/status_check_collector.rs
Normal file
|
@ -0,0 +1,52 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use tracing::{debug_span, error};
|
||||
|
||||
use crate::worker;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub enum StatusCheckRPCMessage {
|
||||
ListStatuses,
|
||||
ListChecks,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct StatusCheckCollector {
|
||||
db_path: PathBuf,
|
||||
}
|
||||
|
||||
impl StatusCheckCollector {
|
||||
pub fn new(db_path: PathBuf) -> Self {
|
||||
Self { db_path }
|
||||
}
|
||||
}
|
||||
|
||||
// RPC API worker
|
||||
impl worker::SimpleWorker for StatusCheckCollector {
|
||||
type J = StatusCheckRPCMessage;
|
||||
|
||||
fn msg_to_job(
|
||||
&mut self,
|
||||
_method: &str,
|
||||
_headers: &Option<String>,
|
||||
body: &[u8],
|
||||
) -> Result<Self::J, String> {
|
||||
match serde_json::from_slice(body) {
|
||||
Ok(e) => Ok(e),
|
||||
Err(e) => {
|
||||
error!(
|
||||
"Failed to deserialize StatusCheckRPCMessage: {:?}",
|
||||
String::from_utf8(body.to_vec())
|
||||
);
|
||||
panic!("{:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn consumer(&mut self, _chan: &mut lapin::Channel, _job: &Self::J) -> worker::Actions {
|
||||
let span = debug_span!("command");
|
||||
let _enter = span.enter();
|
||||
|
||||
vec![worker::Action::Ack]
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue