From 3b9298ed2b1b2567ccb36a494a21f42d5bcf7946 Mon Sep 17 00:00:00 2001 From: Matt Hill Date: Wed, 3 Apr 2024 11:48:26 -0600 Subject: [PATCH] Feature/dependency autoconfig (#2588) * dependency autoconfig * FE portion --------- Co-authored-by: Aiden McClelland --- core/models/src/procedure_name.rs | 6 +- .../startos/bindings/CurrentDependencyInfo.ts | 1 + .../bindings/DependencyConfigErrors.ts | 4 - core/startos/bindings/Status.ts | 7 +- core/startos/bindings/index.ts | 1 - core/startos/src/context/rpc.rs | 25 ++---- core/startos/src/db/model/package.rs | 1 + core/startos/src/dependencies.rs | 27 +++--- core/startos/src/service/action.rs | 37 ++++++++ core/startos/src/service/config.rs | 51 +++++++++-- core/startos/src/service/control.rs | 2 - core/startos/src/service/dependencies.rs | 61 +++++++++++++ core/startos/src/service/mod.rs | 43 +-------- core/startos/src/service/properties.rs | 21 +++++ .../src/service/service_effect_handler.rs | 89 +++++++++++-------- core/startos/src/service/service_map.rs | 1 - .../startos/src/service/transition/restart.rs | 4 +- core/startos/src/status/mod.rs | 18 ---- core/startos/src/util/actor.rs | 7 +- sdk/lib/types.ts | 2 +- .../ui/src/app/services/api/api.fixures.ts | 8 +- .../ui/src/app/services/api/mock-patch.ts | 6 +- .../ui/src/app/services/dep-error.service.ts | 10 +-- 23 files changed, 262 insertions(+), 170 deletions(-) delete mode 100644 core/startos/bindings/DependencyConfigErrors.ts create mode 100644 core/startos/src/service/action.rs create mode 100644 core/startos/src/service/dependencies.rs create mode 100644 core/startos/src/service/properties.rs diff --git a/core/models/src/procedure_name.rs b/core/models/src/procedure_name.rs index c42068be3..c8ae8c3a8 100644 --- a/core/models/src/procedure_name.rs +++ b/core/models/src/procedure_name.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -use crate::ActionId; +use crate::{ActionId, PackageId}; #[derive(Debug, Clone, Serialize, Deserialize)] pub enum ProcedureName { @@ -14,8 +14,8 @@ pub enum ProcedureName { ActionMetadata, RunAction(ActionId), GetAction(ActionId), - QueryDependency(ActionId), - UpdateDependency(ActionId), + QueryDependency(PackageId), + UpdateDependency(PackageId), Init, Uninit, } diff --git a/core/startos/bindings/CurrentDependencyInfo.ts b/core/startos/bindings/CurrentDependencyInfo.ts index 10112e312..8b2b0100d 100644 --- a/core/startos/bindings/CurrentDependencyInfo.ts +++ b/core/startos/bindings/CurrentDependencyInfo.ts @@ -6,4 +6,5 @@ export type CurrentDependencyInfo = { icon: DataUrl; registryUrl: string; versionSpec: string; + configSatisfied: boolean; } & ({ kind: "exists" } | { kind: "running"; healthChecks: string[] }); diff --git a/core/startos/bindings/DependencyConfigErrors.ts b/core/startos/bindings/DependencyConfigErrors.ts deleted file mode 100644 index 5f2246fa9..000000000 --- a/core/startos/bindings/DependencyConfigErrors.ts +++ /dev/null @@ -1,4 +0,0 @@ -// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { PackageId } from "./PackageId"; - -export type DependencyConfigErrors = { [key: PackageId]: string }; diff --git a/core/startos/bindings/Status.ts b/core/startos/bindings/Status.ts index e23c5b4be..6b240347d 100644 --- a/core/startos/bindings/Status.ts +++ b/core/startos/bindings/Status.ts @@ -1,9 +1,4 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { DependencyConfigErrors } from "./DependencyConfigErrors"; import type { MainStatus } from "./MainStatus"; -export type Status = { - configured: boolean; - main: MainStatus; - dependencyConfigErrors: DependencyConfigErrors; -}; +export type Status = { configured: boolean; main: MainStatus }; diff --git a/core/startos/bindings/index.ts b/core/startos/bindings/index.ts index 4ce0ab643..fd422a2f5 100644 --- a/core/startos/bindings/index.ts +++ b/core/startos/bindings/index.ts @@ -18,7 +18,6 @@ export { CurrentDependencies } from "./CurrentDependencies"; export { CurrentDependencyInfo } from "./CurrentDependencyInfo"; export { DataUrl } from "./DataUrl"; export { Dependencies } from "./Dependencies"; -export { DependencyConfigErrors } from "./DependencyConfigErrors"; export { DependencyKind } from "./DependencyKind"; export { DependencyRequirement } from "./DependencyRequirement"; export { DepInfo } from "./DepInfo"; diff --git a/core/startos/src/context/rpc.rs b/core/startos/src/context/rpc.rs index 6450eb561..a51e23b08 100644 --- a/core/startos/src/context/rpc.rs +++ b/core/startos/src/context/rpc.rs @@ -209,33 +209,24 @@ impl RpcContext { self.services.init(&self).await?; tracing::info!("Initialized Package Managers"); - let mut all_dependency_config_errs = BTreeMap::new(); + let mut updated_current_dependents = BTreeMap::new(); let peek = self.db.peek().await; for (package_id, package) in peek.as_public().as_package_data().as_entries()?.into_iter() { let package = package.clone(); - let current_dependencies = package.as_current_dependencies().de()?; - all_dependency_config_errs.insert( - package_id.clone(), - compute_dependency_config_errs( - self, - &peek, - &package_id, - ¤t_dependencies, - &Default::default(), - ) - .await?, - ); + let mut current_dependencies = package.as_current_dependencies().de()?; + compute_dependency_config_errs(self, &package_id, &mut current_dependencies).await?; + updated_current_dependents.insert(package_id.clone(), current_dependencies); } self.db .mutate(|v| { - for (package_id, errs) in all_dependency_config_errs { - if let Some(config_errors) = v + for (package_id, deps) in updated_current_dependents { + if let Some(model) = v .as_public_mut() .as_package_data_mut() .as_idx_mut(&package_id) - .map(|i| i.as_status_mut().as_dependency_config_errors_mut()) + .map(|i| i.as_current_dependencies_mut()) { - config_errors.ser(&errs)?; + model.ser(&deps)?; } } Ok(()) diff --git a/core/startos/src/db/model/package.rs b/core/startos/src/db/model/package.rs index 83a35d086..29b7bb90f 100644 --- a/core/startos/src/db/model/package.rs +++ b/core/startos/src/db/model/package.rs @@ -380,6 +380,7 @@ pub struct CurrentDependencyInfo { pub registry_url: Url, #[ts(type = "string")] pub version_spec: VersionRange, + pub config_satisfied: bool, } #[derive(Clone, Debug, Deserialize, Serialize, TS)] diff --git a/core/startos/src/dependencies.rs b/core/startos/src/dependencies.rs index 69e4cad59..61f5af2b4 100644 --- a/core/startos/src/dependencies.rs +++ b/core/startos/src/dependencies.rs @@ -12,7 +12,6 @@ use crate::config::{Config, ConfigSpec, ConfigureContext}; use crate::context::RpcContext; use crate::db::model::package::CurrentDependencies; use crate::prelude::*; -use crate::status::DependencyConfigErrors; use crate::Error; pub fn dependency() -> ParentHandler { @@ -180,17 +179,23 @@ pub async fn configure_logic( #[instrument(skip_all)] pub async fn compute_dependency_config_errs( ctx: &RpcContext, - db: &Peeked, id: &PackageId, - current_dependencies: &CurrentDependencies, - dependency_config: &BTreeMap, -) -> Result { - let mut dependency_config_errs = BTreeMap::new(); - for (dependency, _dep_info) in current_dependencies.0.iter() { + current_dependencies: &mut CurrentDependencies, +) -> Result<(), Error> { + let service_guard = ctx.services.get(id).await; + let service = service_guard.as_ref().or_not_found(id)?; + for (dep_id, dep_info) in current_dependencies.0.iter_mut() { // check if config passes dependency check - if let Some(error) = todo!() { - dependency_config_errs.insert(dependency.clone(), error); - } + let Some(dependency) = &*ctx.services.get(dep_id).await else { + continue; + }; + + let dep_config = dependency.get_config().await?.config; + + dep_info.config_satisfied = service + .dependency_config(dep_id.clone(), dep_config) + .await? + .is_none(); } - Ok(DependencyConfigErrors(dependency_config_errs)) + Ok(()) } diff --git a/core/startos/src/service/action.rs b/core/startos/src/service/action.rs new file mode 100644 index 000000000..a33869222 --- /dev/null +++ b/core/startos/src/service/action.rs @@ -0,0 +1,37 @@ +use std::time::Duration; + +use models::{ActionId, ProcedureName}; + +use crate::action::ActionResult; +use crate::prelude::*; +use crate::service::{Service, ServiceActor}; +use crate::util::actor::{BackgroundJobs, Handler}; + +struct Action { + id: ActionId, + input: Value, +} +impl Handler for ServiceActor { + type Response = Result; + async fn handle( + &mut self, + Action { id, input }: Action, + _: &mut BackgroundJobs, + ) -> Self::Response { + let container = &self.0.persistent_container; + container + .execute::( + ProcedureName::RunAction(id), + input, + Some(Duration::from_secs(30)), + ) + .await + .with_kind(ErrorKind::Action) + } +} + +impl Service { + pub async fn action(&self, id: ActionId, input: Value) -> Result { + self.actor.send(Action { id, input }).await? + } +} diff --git a/core/startos/src/service/config.rs b/core/startos/src/service/config.rs index e1294a465..df3e5b046 100644 --- a/core/startos/src/service/config.rs +++ b/core/startos/src/service/config.rs @@ -1,19 +1,52 @@ +use std::time::Duration; + use models::ProcedureName; +use crate::config::action::ConfigRes; use crate::config::ConfigureContext; use crate::prelude::*; -use crate::service::Service; +use crate::service::{Service, ServiceActor}; +use crate::util::actor::{BackgroundJobs, Handler}; +use crate::util::serde::NoOutput; -impl Service { - pub async fn configure( - &self, - ConfigureContext { timeout, config }: ConfigureContext, - ) -> Result<(), Error> { - let container = &self.seed.persistent_container; +struct Configure(ConfigureContext); +impl Handler for ServiceActor { + type Response = Result<(), Error>; + async fn handle( + &mut self, + Configure(ConfigureContext { timeout, config }): Configure, + _: &mut BackgroundJobs, + ) -> Self::Response { + let container = &self.0.persistent_container; container - .execute::(ProcedureName::SetConfig, to_value(&config)?, timeout) + .execute::(ProcedureName::SetConfig, to_value(&config)?, timeout) .await - .with_kind(ErrorKind::Action)?; + .with_kind(ErrorKind::ConfigRulesViolation)?; Ok(()) } } + +struct GetConfig; +impl Handler for ServiceActor { + type Response = Result; + async fn handle(&mut self, _: GetConfig, _: &mut BackgroundJobs) -> Self::Response { + let container = &self.0.persistent_container; + container + .execute::( + ProcedureName::GetConfig, + Value::Null, + Some(Duration::from_secs(30)), // TODO timeout + ) + .await + .with_kind(ErrorKind::ConfigGen) + } +} + +impl Service { + pub async fn configure(&self, ctx: ConfigureContext) -> Result<(), Error> { + self.actor.send(Configure(ctx)).await? + } + pub async fn get_config(&self) -> Result { + self.actor.send(GetConfig).await? + } +} diff --git a/core/startos/src/service/control.rs b/core/startos/src/service/control.rs index 88d66d97c..5ef0bbff2 100644 --- a/core/startos/src/service/control.rs +++ b/core/startos/src/service/control.rs @@ -5,7 +5,6 @@ use crate::service::{Service, ServiceActor}; use crate::util::actor::{BackgroundJobs, Handler}; struct Start; -#[async_trait::async_trait] impl Handler for ServiceActor { type Response = (); async fn handle(&mut self, _: Start, _: &mut BackgroundJobs) -> Self::Response { @@ -22,7 +21,6 @@ impl Service { } struct Stop; -#[async_trait::async_trait] impl Handler for ServiceActor { type Response = (); async fn handle(&mut self, _: Stop, _: &mut BackgroundJobs) -> Self::Response { diff --git a/core/startos/src/service/dependencies.rs b/core/startos/src/service/dependencies.rs new file mode 100644 index 000000000..67cc5d53f --- /dev/null +++ b/core/startos/src/service/dependencies.rs @@ -0,0 +1,61 @@ +use std::time::Duration; + +use imbl_value::json; +use models::{PackageId, ProcedureName}; + +use crate::prelude::*; +use crate::service::{Service, ServiceActor}; +use crate::util::actor::{BackgroundJobs, Handler}; +use crate::Config; + +struct DependencyConfig { + dependency_id: PackageId, + remote_config: Option, +} +impl Handler for ServiceActor { + type Response = Result, Error>; + async fn handle( + &mut self, + DependencyConfig { + dependency_id, + remote_config, + }: DependencyConfig, + _: &mut BackgroundJobs, + ) -> Self::Response { + let container = &self.0.persistent_container; + container + .sanboxed::>( + ProcedureName::UpdateDependency(dependency_id.clone()), + json!({ + "queryResults": container + .execute::( + ProcedureName::QueryDependency(dependency_id), + Value::Null, + Some(Duration::from_secs(30)), + ) + .await + .with_kind(ErrorKind::Dependency)?, + "remoteConfig": remote_config, + }), + Some(Duration::from_secs(30)), + ) + .await + .with_kind(ErrorKind::Dependency) + .map(|res| res.filter(|c| !c.is_empty())) + } +} + +impl Service { + pub async fn dependency_config( + &self, + dependency_id: PackageId, + remote_config: Option, + ) -> Result, Error> { + self.actor + .send(DependencyConfig { + dependency_id, + remote_config, + }) + .await? + } +} diff --git a/core/startos/src/service/mod.rs b/core/startos/src/service/mod.rs index 95d507bfa..2b430dc73 100644 --- a/core/startos/src/service/mod.rs +++ b/core/startos/src/service/mod.rs @@ -5,7 +5,7 @@ use chrono::{DateTime, Utc}; use clap::Parser; use futures::future::BoxFuture; use imbl::OrdMap; -use models::{ActionId, HealthCheckId, PackageId, ProcedureName}; +use models::{HealthCheckId, PackageId, ProcedureName}; use persistent_container::PersistentContainer; use rpc_toolkit::{from_fn_async, CallRemoteHandler, Empty, Handler, HandlerArgs}; use serde::{Deserialize, Serialize}; @@ -13,7 +13,6 @@ use start_stop::StartStop; use tokio::sync::Notify; use ts_rs::TS; -use crate::action::ActionResult; use crate::config::action::ConfigRes; use crate::context::{CliContext, RpcContext}; use crate::core::rpc_continuations::RequestGuid; @@ -33,10 +32,13 @@ use crate::util::actor::{Actor, BackgroundJobs, SimpleActor}; use crate::util::serde::Pem; use crate::volume::data_dir; +mod action; pub mod cli; mod config; mod control; +mod dependencies; pub mod persistent_container; +mod properties; mod rpc; pub mod service_effect_handler; pub mod service_map; @@ -302,43 +304,6 @@ impl Service { Err(Error::new(eyre!("not yet implemented"), ErrorKind::Unknown)) } - pub async fn get_config(&self) -> Result { - let container = &self.seed.persistent_container; - container - .execute::( - ProcedureName::GetConfig, - Value::Null, - Some(Duration::from_secs(30)), // TODO timeout - ) - .await - .with_kind(ErrorKind::ConfigGen) - } - - // TODO DO the Action Get - - pub async fn action(&self, id: ActionId, input: Value) -> Result { - let container = &self.seed.persistent_container; - container - .execute::( - ProcedureName::RunAction(id), - input, - Some(Duration::from_secs(30)), - ) - .await - .with_kind(ErrorKind::Action) - } - pub async fn properties(&self) -> Result { - let container = &self.seed.persistent_container; - container - .execute::( - ProcedureName::Properties, - Value::Null, - Some(Duration::from_secs(30)), - ) - .await - .with_kind(ErrorKind::Unknown) - } - pub async fn shutdown(self) -> Result<(), Error> { self.actor .shutdown(crate::util::actor::PendingMessageStrategy::FinishAll { timeout: None }) // TODO timeout diff --git a/core/startos/src/service/properties.rs b/core/startos/src/service/properties.rs new file mode 100644 index 000000000..3e795207a --- /dev/null +++ b/core/startos/src/service/properties.rs @@ -0,0 +1,21 @@ +use std::time::Duration; + +use models::ProcedureName; + +use crate::prelude::*; +use crate::service::Service; + +impl Service { + // TODO: leave here or switch to Actor Message? + pub async fn properties(&self) -> Result { + let container = &self.seed.persistent_container; + container + .execute::( + ProcedureName::Properties, + Value::Null, + Some(Duration::from_secs(30)), + ) + .await + .with_kind(ErrorKind::Unknown) + } +} diff --git a/core/startos/src/service/service_effect_handler.rs b/core/startos/src/service/service_effect_handler.rs index 4041cbb98..210c3d07c 100644 --- a/core/startos/src/service/service_effect_handler.rs +++ b/core/startos/src/service/service_effect_handler.rs @@ -1,4 +1,4 @@ -use std::collections::BTreeSet; +use std::collections::{BTreeMap, BTreeSet}; use std::ffi::OsString; use std::net::Ipv4Addr; use std::os::unix::process::CommandExt; @@ -1120,51 +1120,64 @@ async fn set_dependencies( ) -> Result<(), Error> { let ctx = ctx.deref()?; let id = &ctx.id; + let service_guard = ctx.ctx.services.get(id).await; + let service = service_guard.as_ref().or_not_found(id)?; + let mut deps = BTreeMap::new(); + for dependency in dependencies { + let (dep_id, kind, registry_url, version_spec) = match dependency { + DependencyRequirement::Exists { + id, + registry_url, + version_spec, + } => ( + id, + CurrentDependencyKind::Exists, + registry_url, + version_spec, + ), + DependencyRequirement::Running { + id, + health_checks, + registry_url, + version_spec, + } => ( + id, + CurrentDependencyKind::Running { health_checks }, + registry_url, + version_spec, + ), + }; + let icon = todo!(); + let title = todo!(); + let config_satisfied = if let Some(dep_service) = &*ctx.ctx.services.get(&dep_id).await { + service + .dependency_config(dep_id, dep_service.get_config().await?.config) + .await? + .is_none() + } else { + true + }; + deps.insert( + dep_id, + CurrentDependencyInfo { + kind: CurrentDependencyKind::Exists, + registry_url, + version_spec, + icon, + title, + config_satisfied, + }, + ); + } ctx.ctx .db .mutate(|db| { - let dependencies = CurrentDependencies( - dependencies - .into_iter() - .map(|dependency| match dependency { - DependencyRequirement::Exists { - id, - registry_url, - version_spec, - } => ( - id, - CurrentDependencyInfo { - kind: CurrentDependencyKind::Exists, - registry_url, - version_spec, - icon: todo!(), - title: todo!(), - }, - ), - DependencyRequirement::Running { - id, - health_checks, - registry_url, - version_spec, - } => ( - id, - CurrentDependencyInfo { - kind: CurrentDependencyKind::Running { health_checks }, - registry_url, - version_spec, - icon: todo!(), - title: todo!(), - }, - ), - }) - .collect(), - ); db.as_public_mut() .as_package_data_mut() .as_idx_mut(id) .or_not_found(id)? .as_current_dependencies_mut() - .ser(&dependencies) + .ser(&CurrentDependencies(deps)) }) .await } diff --git a/core/startos/src/service/service_map.rs b/core/startos/src/service/service_map.rs index 934497eb9..68e1fc8a8 100644 --- a/core/startos/src/service/service_map.rs +++ b/core/startos/src/service/service_map.rs @@ -165,7 +165,6 @@ impl ServiceMap { status: Status { configured: false, main: MainStatus::Stopped, - dependency_config_errors: Default::default(), }, marketplace_url: None, developer_key: Pem::new(developer_key), diff --git a/core/startos/src/service/transition/restart.rs b/core/startos/src/service/transition/restart.rs index 9c82d0282..7047bd18f 100644 --- a/core/startos/src/service/transition/restart.rs +++ b/core/startos/src/service/transition/restart.rs @@ -2,16 +2,14 @@ use std::sync::Arc; use futures::FutureExt; +use super::TempDesiredState; use crate::prelude::*; use crate::service::transition::{TransitionKind, TransitionState}; use crate::service::{Service, ServiceActor}; use crate::util::actor::{BackgroundJobs, Handler}; use crate::util::future::RemoteCancellable; -use super::TempDesiredState; - struct Restart; -#[async_trait::async_trait] impl Handler for ServiceActor { type Response = (); async fn handle(&mut self, _: Restart, jobs: &mut BackgroundJobs) -> Self::Response { diff --git a/core/startos/src/status/mod.rs b/core/startos/src/status/mod.rs index 2faa90e79..645c082f4 100644 --- a/core/startos/src/status/mod.rs +++ b/core/startos/src/status/mod.rs @@ -2,7 +2,6 @@ use std::collections::BTreeMap; use chrono::{DateTime, Utc}; use imbl::OrdMap; -use models::PackageId; use serde::{Deserialize, Serialize}; use ts_rs::TS; @@ -18,23 +17,6 @@ pub mod health_check; pub struct Status { pub configured: bool, pub main: MainStatus, - #[serde(default)] - pub dependency_config_errors: DependencyConfigErrors, -} - -#[derive(Clone, Debug, Deserialize, Serialize, HasModel, Default, TS)] -#[model = "Model"] -#[ts(export)] -pub struct DependencyConfigErrors(pub BTreeMap); -impl Map for DependencyConfigErrors { - type Key = PackageId; - type Value = String; - fn key_str(key: &Self::Key) -> Result, Error> { - Ok(key) - } - fn key_string(key: &Self::Key) -> Result { - Ok(key.clone().into()) - } } #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, TS)] diff --git a/core/startos/src/util/actor.rs b/core/startos/src/util/actor.rs index 8e08a1d53..caa83d8b1 100644 --- a/core/startos/src/util/actor.rs +++ b/core/startos/src/util/actor.rs @@ -16,10 +16,13 @@ pub trait Actor: Send + 'static { fn init(&mut self, jobs: &mut BackgroundJobs) {} } -#[async_trait::async_trait] pub trait Handler: Actor { type Response: Any + Send; - async fn handle(&mut self, msg: M, jobs: &mut BackgroundJobs) -> Self::Response; + fn handle( + &mut self, + msg: M, + jobs: &mut BackgroundJobs, + ) -> impl Future + Send; } #[async_trait::async_trait] diff --git a/sdk/lib/types.ts b/sdk/lib/types.ts index c801d56cd..b921a40af 100644 --- a/sdk/lib/types.ts +++ b/sdk/lib/types.ts @@ -110,7 +110,7 @@ export type VersionString = string */ export type DependencyConfig = { /** During autoconfigure, we have access to effects and local data. We are going to figure out all the data that we need and send it to update. For the sdk it is the desired delta */ - query(options: { effects: Effects; localConfig: unknown }): Promise + query(options: { effects: Effects }): Promise /** This is the second part. Given the query results off the previous function, we will determine what to change the remote config to. In our sdk normall we are going to use the previous as a deep merge. */ update(options: { queryResults: unknown diff --git a/web/projects/ui/src/app/services/api/api.fixures.ts b/web/projects/ui/src/app/services/api/api.fixures.ts index f06980f20..7933109b3 100644 --- a/web/projects/ui/src/app/services/api/api.fixures.ts +++ b/web/projects/ui/src/app/services/api/api.fixures.ts @@ -1410,7 +1410,6 @@ export module Mock { started: new Date().toISOString(), health: {}, }, - dependencyConfigErrors: {}, }, actions: {}, // @TODO need mocks serviceInterfaces: { @@ -1650,7 +1649,6 @@ export module Mock { main: { status: 'stopped', }, - dependencyConfigErrors: {}, }, actions: {}, serviceInterfaces: { @@ -1770,6 +1768,7 @@ export module Mock { registryUrl: '', versionSpec: '>=26.0.0', healthChecks: [], + configSatisfied: true, }, }, hosts: {}, @@ -1790,9 +1789,6 @@ export module Mock { main: { status: 'stopped', }, - dependencyConfigErrors: { - 'btc-rpc-proxy': 'Username not found', - }, }, actions: {}, serviceInterfaces: { @@ -2015,6 +2011,7 @@ export module Mock { registryUrl: 'https://registry.start9.com', versionSpec: '>=26.0.0', healthChecks: [], + configSatisfied: true, }, 'btc-rpc-proxy': { title: Mock.MockManifestBitcoinProxy.title, @@ -2022,6 +2019,7 @@ export module Mock { kind: 'exists', registryUrl: 'https://community-registry.start9.com', versionSpec: '>2.0.0', // @TODO + configSatisfied: false, }, }, hosts: {}, diff --git a/web/projects/ui/src/app/services/api/mock-patch.ts b/web/projects/ui/src/app/services/api/mock-patch.ts index 00c200440..8a3f714d1 100644 --- a/web/projects/ui/src/app/services/api/mock-patch.ts +++ b/web/projects/ui/src/app/services/api/mock-patch.ts @@ -125,7 +125,6 @@ export const mockPatchData: DataModel = { }, }, }, - dependencyConfigErrors: {}, }, actions: {}, // @TODO serviceInterfaces: { @@ -367,9 +366,6 @@ export const mockPatchData: DataModel = { main: { status: 'stopped', }, - dependencyConfigErrors: { - 'btc-rpc-proxy': 'This is a config unsatisfied error', - }, }, actions: {}, serviceInterfaces: { @@ -590,6 +586,7 @@ export const mockPatchData: DataModel = { registryUrl: 'https://registry.start9.com', versionSpec: '>=26.0.0', healthChecks: [], + configSatisfied: true, }, 'btc-rpc-proxy': { title: 'Bitcoin Proxy', @@ -598,6 +595,7 @@ export const mockPatchData: DataModel = { registryUrl: 'https://community-registry.start9.com', versionSpec: '>2.0.0', healthChecks: [], + configSatisfied: false, }, }, hosts: {}, diff --git a/web/projects/ui/src/app/services/dep-error.service.ts b/web/projects/ui/src/app/services/dep-error.service.ts index 987499a5d..5abee0d6b 100644 --- a/web/projects/ui/src/app/services/dep-error.service.ts +++ b/web/projects/ui/src/app/services/dep-error.service.ts @@ -83,20 +83,20 @@ export class DepErrorService { } } - const versionSpec = pkg.currentDependencies[depId].versionSpec + const currentDep = pkg.currentDependencies[depId] const depManifest = dep.stateInfo.manifest // incorrect version - if (!this.emver.satisfies(depManifest.version, versionSpec)) { + if (!this.emver.satisfies(depManifest.version, currentDep.versionSpec)) { return { type: 'incorrectVersion', - expected: versionSpec, + expected: currentDep.versionSpec, received: depManifest.version, } } // invalid config - if (Object.values(pkg.status.dependencyConfigErrors).some(err => !!err)) { + if (!currentDep.configSatisfied) { return { type: 'configUnsatisfied', } @@ -111,8 +111,6 @@ export class DepErrorService { } } - const currentDep = pkg.currentDependencies[depId] - // health check failure if (depStatus === 'running' && currentDep.kind === 'running') { for (let id of currentDep.healthChecks) {