mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-04-02 05:23:14 +00:00
rename appmgr
This commit is contained in:
committed by
Aiden McClelland
parent
9cf379f9ee
commit
edde478382
136
backend/src/status/health_check.rs
Normal file
136
backend/src/status/health_check.rs
Normal file
@@ -0,0 +1,136 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::path::Path;
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::action::{ActionImplementation, NoOutput};
|
||||
use crate::context::RpcContext;
|
||||
use crate::id::Id;
|
||||
use crate::s9pk::manifest::PackageId;
|
||||
use crate::util::serde::Duration;
|
||||
use crate::util::Version;
|
||||
use crate::volume::Volumes;
|
||||
use crate::Error;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
|
||||
pub struct HealthCheckId<S: AsRef<str> = String>(Id<S>);
|
||||
impl<S: AsRef<str>> std::fmt::Display for HealthCheckId<S> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", &self.0)
|
||||
}
|
||||
}
|
||||
impl<S: AsRef<str>> AsRef<str> for HealthCheckId<S> {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
impl<'de, S> Deserialize<'de> for HealthCheckId<S>
|
||||
where
|
||||
S: AsRef<str>,
|
||||
Id<S>: Deserialize<'de>,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Ok(HealthCheckId(Deserialize::deserialize(deserializer)?))
|
||||
}
|
||||
}
|
||||
impl<S: AsRef<str>> AsRef<Path> for HealthCheckId<S> {
|
||||
fn as_ref(&self) -> &Path {
|
||||
self.0.as_ref().as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct HealthChecks(pub BTreeMap<HealthCheckId, HealthCheck>);
|
||||
impl HealthChecks {
|
||||
pub async fn check_all(
|
||||
&self,
|
||||
ctx: &RpcContext,
|
||||
started: DateTime<Utc>,
|
||||
pkg_id: &PackageId,
|
||||
pkg_version: &Version,
|
||||
volumes: &Volumes,
|
||||
) -> Result<BTreeMap<HealthCheckId, HealthCheckResult>, Error> {
|
||||
let res = futures::future::try_join_all(self.0.iter().map(|(id, check)| async move {
|
||||
Ok::<_, Error>((
|
||||
id.clone(),
|
||||
check
|
||||
.check(ctx, id, started, pkg_id, pkg_version, volumes)
|
||||
.await?,
|
||||
))
|
||||
}))
|
||||
.await?;
|
||||
Ok(res.into_iter().collect())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct HealthCheck {
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
#[serde(flatten)]
|
||||
implementation: ActionImplementation,
|
||||
pub timeout: Option<Duration>,
|
||||
}
|
||||
impl HealthCheck {
|
||||
#[instrument(skip(ctx))]
|
||||
pub async fn check(
|
||||
&self,
|
||||
ctx: &RpcContext,
|
||||
id: &HealthCheckId,
|
||||
started: DateTime<Utc>,
|
||||
pkg_id: &PackageId,
|
||||
pkg_version: &Version,
|
||||
volumes: &Volumes,
|
||||
) -> Result<HealthCheckResult, Error> {
|
||||
let res = self
|
||||
.implementation
|
||||
.execute(
|
||||
ctx,
|
||||
pkg_id,
|
||||
pkg_version,
|
||||
Some(&format!("{}Health", id)),
|
||||
volumes,
|
||||
Some(Utc::now().signed_duration_since(started).num_milliseconds()),
|
||||
true,
|
||||
Some(
|
||||
self.timeout
|
||||
.map_or(std::time::Duration::from_secs(30), |d| *d),
|
||||
),
|
||||
)
|
||||
.await?;
|
||||
Ok(match res {
|
||||
Ok(NoOutput) => HealthCheckResult::Success,
|
||||
Err((59, _)) => HealthCheckResult::Disabled,
|
||||
Err((60, _)) => HealthCheckResult::Starting,
|
||||
Err((61, message)) => HealthCheckResult::Loading { message },
|
||||
Err((_, error)) => HealthCheckResult::Failure { error },
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
#[serde(tag = "result")]
|
||||
pub enum HealthCheckResult {
|
||||
Success,
|
||||
Disabled,
|
||||
Starting,
|
||||
Loading { message: String },
|
||||
Failure { error: String },
|
||||
}
|
||||
impl std::fmt::Display for HealthCheckResult {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
HealthCheckResult::Success => write!(f, "Succeeded"),
|
||||
HealthCheckResult::Disabled => write!(f, "Disabled"),
|
||||
HealthCheckResult::Starting => write!(f, "Starting"),
|
||||
HealthCheckResult::Loading { message } => write!(f, "Loading ({})", message),
|
||||
HealthCheckResult::Failure { error } => write!(f, "Failed ({})", error),
|
||||
}
|
||||
}
|
||||
}
|
||||
67
backend/src/status/mod.rs
Normal file
67
backend/src/status/mod.rs
Normal file
@@ -0,0 +1,67 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use patch_db::{HasModel, Model};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use self::health_check::HealthCheckId;
|
||||
use crate::dependencies::DependencyErrors;
|
||||
use crate::status::health_check::HealthCheckResult;
|
||||
|
||||
pub mod health_check;
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, HasModel)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct Status {
|
||||
pub configured: bool,
|
||||
#[model]
|
||||
pub main: MainStatus,
|
||||
#[model]
|
||||
pub dependency_errors: DependencyErrors,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, HasModel)]
|
||||
#[serde(tag = "status")]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum MainStatus {
|
||||
Stopped,
|
||||
Stopping,
|
||||
Starting,
|
||||
Running {
|
||||
started: DateTime<Utc>,
|
||||
health: BTreeMap<HealthCheckId, HealthCheckResult>,
|
||||
},
|
||||
BackingUp {
|
||||
started: Option<DateTime<Utc>>,
|
||||
health: BTreeMap<HealthCheckId, HealthCheckResult>,
|
||||
},
|
||||
}
|
||||
impl MainStatus {
|
||||
pub fn running(&self) -> bool {
|
||||
match self {
|
||||
MainStatus::Starting
|
||||
| MainStatus::Running { .. }
|
||||
| MainStatus::BackingUp {
|
||||
started: Some(_), ..
|
||||
} => true,
|
||||
MainStatus::Stopped
|
||||
| MainStatus::Stopping
|
||||
| MainStatus::BackingUp { started: None, .. } => false,
|
||||
}
|
||||
}
|
||||
pub fn stop(&mut self) {
|
||||
match self {
|
||||
MainStatus::Starting | MainStatus::Running { .. } => {
|
||||
*self = MainStatus::Stopping;
|
||||
}
|
||||
MainStatus::BackingUp { started, .. } => {
|
||||
*started = None;
|
||||
}
|
||||
MainStatus::Stopped | MainStatus::Stopping => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl MainStatusModel {
|
||||
pub fn started(self) -> Model<Option<DateTime<Utc>>> {
|
||||
self.0.child("started")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user