feat: ApplicationModule with tentative architecture and placeholder implementation of first few features
This commit is contained in:
parent
22847fc42a
commit
923de4506e
75
harmony/src/modules/application/features/endpoint.rs
Normal file
75
harmony/src/modules/application/features/endpoint.rs
Normal file
@ -0,0 +1,75 @@
|
||||
use async_trait::async_trait;
|
||||
|
||||
use crate::modules::application::{Application, ApplicationFeature};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PublicEndpoint {
|
||||
application_port: u16,
|
||||
}
|
||||
|
||||
/// Use port 3000 as default port. Harmony wants to provide "sane defaults" in general, and in this
|
||||
/// particular context, using port 80 goes against our philosophy to provide production grade
|
||||
/// defaults out of the box. Using an unprivileged port is a good security practice and will allow
|
||||
/// for unprivileged containers to work with this out of the box.
|
||||
///
|
||||
/// Now, why 3000 specifically? Many popular web/network frameworks use it by default, there is no
|
||||
/// perfect answer for this but many Rust and Python libraries tend to use 3000.
|
||||
impl Default for PublicEndpoint {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
application_port: 3000,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl ApplicationFeature for PublicEndpoint {
|
||||
async fn ensure_installed(&self) -> Result<(), String> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn is_installed(&self) -> Result<bool, String> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn uninstall(&self) -> Result<(), String> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
// Design options here :
|
||||
//
|
||||
// 1. Forget about ApplicationFeature trait. The Features are just other scores that are passed on to
|
||||
// the ApplicationInterpret as children (and we can rename children dependencies maybe?)
|
||||
//
|
||||
// 2. Go forward with the ApplicationFeature trait. There are important question marks here :
|
||||
// - What about the installation lifecycle management? This was defined as being handled by a
|
||||
// Topology. The thing here is that I am not sure wether application features belong at the
|
||||
// Topology level or not. Functionnaly they are pretty similar. Topology provides software
|
||||
// infrastructure features that Scores will then install themselves on. Most of the time those very
|
||||
// features are installed using Scores with lower level dependencies. For example, :
|
||||
//
|
||||
// AlertingFeature depends on T: Topology + AlertSender
|
||||
// AlertSender is implemented as KubePrometheus which depends on T: Topology + HelmCommand
|
||||
// HelmCommand relies on T: Topology + K8sClient
|
||||
//
|
||||
// With that said, would it work with `features: Vec<box dyn Score<T>>` instead of `features:
|
||||
// Vec<box dyn ApplicationFeature>>` ?
|
||||
//
|
||||
// Let's unpack this :
|
||||
//
|
||||
// RustWebappScore<T: Topology> {
|
||||
// features: Vec<box dyn Score<T>>,
|
||||
// }
|
||||
//
|
||||
// This brings in a significant problem : RustWebappScore becomes generic, which is a problem for
|
||||
// Clone and Serialize bounds.
|
||||
//
|
||||
// But that can be fixed easily I think ?
|
||||
//
|
||||
// RustWebappScore<T: Topology + Clone + Serialize> {
|
||||
// features: Vec<box dyn Score<T>>,
|
||||
// }
|
||||
//
|
||||
// Oh right not quite because it is `dyn`.
|
||||
//
|
||||
54
harmony/src/modules/application/features/mod.rs
Normal file
54
harmony/src/modules/application/features/mod.rs
Normal file
@ -0,0 +1,54 @@
|
||||
mod endpoint;
|
||||
use async_trait::async_trait;
|
||||
pub use endpoint::*;
|
||||
|
||||
use super::ApplicationFeature;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct SoftwareQualityChecks {}
|
||||
|
||||
#[async_trait]
|
||||
impl ApplicationFeature for SoftwareQualityChecks {
|
||||
async fn ensure_installed(&self) -> Result<(), String> {
|
||||
todo!()
|
||||
}
|
||||
async fn is_installed(&self) -> Result<bool, String> {
|
||||
todo!()
|
||||
}
|
||||
async fn uninstall(&self) -> Result<(), String> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ContinuousDelivery {}
|
||||
|
||||
#[async_trait]
|
||||
impl ApplicationFeature for ContinuousDelivery {
|
||||
async fn ensure_installed(&self) -> Result<(), String> {
|
||||
todo!()
|
||||
}
|
||||
async fn is_installed(&self) -> Result<bool, String> {
|
||||
todo!()
|
||||
}
|
||||
async fn uninstall(&self) -> Result<(), String> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Monitoring {}
|
||||
|
||||
#[async_trait]
|
||||
impl ApplicationFeature for Monitoring {
|
||||
async fn ensure_installed(&self) -> Result<(), String> {
|
||||
todo!()
|
||||
}
|
||||
async fn is_installed(&self) -> Result<bool, String> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn uninstall(&self) -> Result<(), String> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
@ -1,3 +1,7 @@
|
||||
mod rust;
|
||||
pub mod features;
|
||||
pub use rust::*;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use serde::Serialize;
|
||||
|
||||
@ -29,7 +33,7 @@ impl<T: Topology> Score<T> for GoApplicationScore {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ApplicationInterpret {
|
||||
pub features: Vec<Box<dyn ApplicationFeature>>,
|
||||
features: Vec<Box<dyn ApplicationFeature>>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@ -55,6 +59,8 @@ impl<T: Topology> Interpret<T> for ApplicationInterpret {
|
||||
}
|
||||
}
|
||||
|
||||
trait Application {}
|
||||
|
||||
/// An ApplicationFeature provided by harmony, such as Backups, Monitoring, MultisiteAvailability,
|
||||
/// ContinuousIntegration, ContinuousDelivery
|
||||
#[async_trait]
|
||||
@ -64,6 +70,21 @@ pub trait ApplicationFeature: std::fmt::Debug + Send + Sync {
|
||||
async fn uninstall(&self) -> Result<(), String>;
|
||||
}
|
||||
|
||||
impl Serialize for Box<dyn ApplicationFeature> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Box<dyn ApplicationFeature> {
|
||||
fn clone(&self) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BackupFeature;
|
||||
|
||||
|
||||
26
harmony/src/modules/application/rust.rs
Normal file
26
harmony/src/modules/application/rust.rs
Normal file
@ -0,0 +1,26 @@
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
score::Score,
|
||||
topology::{Topology, Url},
|
||||
};
|
||||
|
||||
use super::{ApplicationFeature, ApplicationInterpret};
|
||||
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
pub struct RustWebappScore {
|
||||
pub name: String,
|
||||
pub domain: Url,
|
||||
pub features: Vec<Box<dyn ApplicationFeature>>,
|
||||
}
|
||||
|
||||
impl<T: Topology> Score<T> for RustWebappScore {
|
||||
fn create_interpret(&self) -> Box<dyn crate::interpret::Interpret<T>> {
|
||||
Box::new(ApplicationInterpret { features: todo!() })
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
format!("{}-RustWebapp", self.name)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user