mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-04-01 21:13:09 +00:00
Refactor/project structure (#3085)
* refactor project structure * environment-based default registry * fix tests * update build container * use docker platform for iso build emulation * simplify compat * Fix docker platform spec in run-compat.sh * handle riscv compat * fix bug with dep error exists attr * undo removal of sorting * use qemu for iso stage --------- Co-authored-by: Mariusz Kogen <k0gen@pm.me> Co-authored-by: Matt Hill <mattnine@protonmail.com>
This commit is contained in:
100
core/src/status/health_check.rs
Normal file
100
core/src/status/health_check.rs
Normal file
@@ -0,0 +1,100 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use clap::builder::ValueParserFactory;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ts_rs::TS;
|
||||
|
||||
pub use crate::HealthCheckId;
|
||||
use crate::util::FromStrParser;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct NamedHealthCheckResult {
|
||||
pub name: String,
|
||||
#[serde(flatten)]
|
||||
pub kind: NamedHealthCheckResultKind,
|
||||
}
|
||||
// healthCheckName:kind:message OR healthCheckName:kind
|
||||
impl FromStr for NamedHealthCheckResult {
|
||||
type Err = color_eyre::eyre::Report;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let from_parts = |name: &str, kind: &str, message: Option<&str>| {
|
||||
let message = message.map(|x| x.to_string());
|
||||
let kind = match kind {
|
||||
"success" => NamedHealthCheckResultKind::Success { message },
|
||||
"disabled" => NamedHealthCheckResultKind::Disabled { message },
|
||||
"starting" => NamedHealthCheckResultKind::Starting { message },
|
||||
"loading" => NamedHealthCheckResultKind::Loading {
|
||||
message: message.unwrap_or_default(),
|
||||
},
|
||||
"failure" => NamedHealthCheckResultKind::Failure {
|
||||
message: message.unwrap_or_default(),
|
||||
},
|
||||
_ => return Err(color_eyre::eyre::eyre!("Invalid health check kind")),
|
||||
};
|
||||
Ok(Self {
|
||||
name: name.to_string(),
|
||||
kind,
|
||||
})
|
||||
};
|
||||
let parts = s.split(':').collect::<Vec<_>>();
|
||||
match &*parts {
|
||||
[name, kind, message] => from_parts(name, kind, Some(message)),
|
||||
[name, kind] => from_parts(name, kind, None),
|
||||
_ => Err(color_eyre::eyre::eyre!(
|
||||
"Could not match the shape of the result ${parts:?}"
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl ValueParserFactory for NamedHealthCheckResult {
|
||||
type Parser = FromStrParser<Self>;
|
||||
fn value_parser() -> Self::Parser {
|
||||
FromStrParser::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(tag = "result")]
|
||||
pub enum NamedHealthCheckResultKind {
|
||||
Success { message: Option<String> },
|
||||
Disabled { message: Option<String> },
|
||||
Starting { message: Option<String> },
|
||||
Loading { message: String },
|
||||
Failure { message: String },
|
||||
}
|
||||
impl std::fmt::Display for NamedHealthCheckResult {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let name = &self.name;
|
||||
match &self.kind {
|
||||
NamedHealthCheckResultKind::Success { message } => {
|
||||
if let Some(message) = message {
|
||||
write!(f, "{name}: Succeeded ({message})")
|
||||
} else {
|
||||
write!(f, "{name}: Succeeded")
|
||||
}
|
||||
}
|
||||
NamedHealthCheckResultKind::Disabled { message } => {
|
||||
if let Some(message) = message {
|
||||
write!(f, "{name}: Disabled ({message})")
|
||||
} else {
|
||||
write!(f, "{name}: Disabled")
|
||||
}
|
||||
}
|
||||
NamedHealthCheckResultKind::Starting { message } => {
|
||||
if let Some(message) = message {
|
||||
write!(f, "{name}: Starting ({message})")
|
||||
} else {
|
||||
write!(f, "{name}: Starting")
|
||||
}
|
||||
}
|
||||
NamedHealthCheckResultKind::Loading { message } => {
|
||||
write!(f, "{name}: Loading ({message})")
|
||||
}
|
||||
NamedHealthCheckResultKind::Failure { message } => {
|
||||
write!(f, "{name}: Failed ({message})")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
143
core/src/status/mod.rs
Normal file
143
core/src/status/mod.rs
Normal file
@@ -0,0 +1,143 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ts_rs::TS;
|
||||
|
||||
use crate::HealthCheckId;
|
||||
use crate::error::ErrorData;
|
||||
use crate::prelude::*;
|
||||
use crate::service::start_stop::StartStop;
|
||||
use crate::status::health_check::NamedHealthCheckResult;
|
||||
|
||||
pub mod health_check;
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize, HasModel, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[model = "Model<Self>"]
|
||||
pub struct StatusInfo {
|
||||
pub health: BTreeMap<HealthCheckId, NamedHealthCheckResult>,
|
||||
pub error: Option<ErrorData>,
|
||||
#[ts(type = "string | null")]
|
||||
pub started: Option<DateTime<Utc>>,
|
||||
pub desired: DesiredStatus,
|
||||
}
|
||||
impl StatusInfo {
|
||||
pub fn stop(&mut self) {
|
||||
self.desired = self.desired.stop();
|
||||
self.health.clear();
|
||||
}
|
||||
}
|
||||
impl Model<StatusInfo> {
|
||||
pub fn start(&mut self) -> Result<(), Error> {
|
||||
self.as_desired_mut().map_mutate(|s| Ok(s.start()))?;
|
||||
Ok(())
|
||||
}
|
||||
pub fn started(&mut self) -> Result<(), Error> {
|
||||
self.as_started_mut()
|
||||
.map_mutate(|s| Ok(Some(s.unwrap_or_else(|| Utc::now()))))?;
|
||||
self.as_desired_mut().map_mutate(|s| {
|
||||
Ok(match s {
|
||||
DesiredStatus::Restarting => DesiredStatus::Running,
|
||||
a => a,
|
||||
})
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
pub fn stop(&mut self) -> Result<(), Error> {
|
||||
self.as_desired_mut().map_mutate(|s| Ok(s.stop()))?;
|
||||
self.as_health_mut().ser(&Default::default())?;
|
||||
Ok(())
|
||||
}
|
||||
pub fn stopped(&mut self) -> Result<(), Error> {
|
||||
self.as_started_mut().ser(&None)?;
|
||||
Ok(())
|
||||
}
|
||||
pub fn init(&mut self) -> Result<(), Error> {
|
||||
self.as_started_mut().ser(&None)?;
|
||||
self.as_desired_mut().map_mutate(|s| {
|
||||
Ok(match s {
|
||||
DesiredStatus::BackingUp {
|
||||
on_complete: StartStop::Start,
|
||||
} => DesiredStatus::Running,
|
||||
DesiredStatus::BackingUp {
|
||||
on_complete: StartStop::Stop,
|
||||
} => DesiredStatus::Stopped,
|
||||
DesiredStatus::Restarting => DesiredStatus::Running,
|
||||
x => x,
|
||||
})
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, TS)]
|
||||
#[serde(tag = "main")]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
#[serde(rename_all_fields = "camelCase")]
|
||||
pub enum DesiredStatus {
|
||||
Stopped,
|
||||
Restarting,
|
||||
Running,
|
||||
BackingUp { on_complete: StartStop },
|
||||
}
|
||||
impl Default for DesiredStatus {
|
||||
fn default() -> Self {
|
||||
Self::Stopped
|
||||
}
|
||||
}
|
||||
impl DesiredStatus {
|
||||
pub fn running(&self) -> bool {
|
||||
match self {
|
||||
Self::Running
|
||||
| Self::Restarting
|
||||
| Self::BackingUp {
|
||||
on_complete: StartStop::Start,
|
||||
} => true,
|
||||
Self::Stopped
|
||||
| Self::BackingUp {
|
||||
on_complete: StartStop::Stop,
|
||||
} => false,
|
||||
}
|
||||
}
|
||||
pub fn run_state(&self) -> StartStop {
|
||||
if self.running() {
|
||||
StartStop::Start
|
||||
} else {
|
||||
StartStop::Stop
|
||||
}
|
||||
}
|
||||
|
||||
pub fn backing_up(&self) -> Self {
|
||||
Self::BackingUp {
|
||||
on_complete: self.run_state(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stop(&self) -> Self {
|
||||
match self {
|
||||
Self::BackingUp { .. } => Self::BackingUp {
|
||||
on_complete: StartStop::Stop,
|
||||
},
|
||||
_ => Self::Stopped,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start(&self) -> Self {
|
||||
match self {
|
||||
Self::BackingUp { .. } => Self::BackingUp {
|
||||
on_complete: StartStop::Start,
|
||||
},
|
||||
Self::Stopped => Self::Running,
|
||||
x => *x,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn restart(&self) -> Self {
|
||||
match self {
|
||||
Self::Running => Self::Restarting,
|
||||
x => *x, // no-op: restart is meaningless in any other state
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user