Skip to content

Commit

Permalink
jeweler: Add Deployment trait
Browse files Browse the repository at this point in the history
  • Loading branch information
sulksamino authored and alerei committed Oct 17, 2024
1 parent 0020c60 commit ba256a8
Show file tree
Hide file tree
Showing 7 changed files with 310 additions and 0 deletions.
94 changes: 94 additions & 0 deletions flecs-core/src/jeweler/app.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
pub use super::Result;
use crate::jeweler::deployment::{Deployment, DeploymentId};
use crate::jeweler::instance::{Instance, InstanceConfig, InstanceId, InstanceStatus};
use crate::vault::pouch::AppKey;
use anyhow::anyhow;
use async_trait::async_trait;
use flecs_app_manifest::AppManifest;
use std::collections::HashMap;
use std::sync::Arc;

type AppId = String;
#[async_trait]
pub trait AppDeployment {
async fn install_app(&self, manifest: &AppManifest) -> Result<AppId>;
async fn uninstall_app(&self, id: AppId) -> Result<()>;
async fn is_app_installed(&self, id: AppId) -> Result<bool>;
}
#[derive(Default)]
pub enum AppStatus {
#[default]
None,
Installed,
NotInstalled,
}

pub struct AppData {
desired: AppStatus,
instances: HashMap<InstanceId, Instance>,
id: Option<AppId>,
deployment: Arc<dyn Deployment>,
}

pub struct App {
key: AppKey,
properties: HashMap<DeploymentId, AppData>,
manifest: Option<Arc<AppManifest>>,
}

impl App {
pub async fn install(&mut self) -> Result<()> {
match &self.manifest {
None => Err(anyhow!(
"Can not install {:?}, no manifest present.",
self.key
))?,
Some(manifest) => {
for data in self.properties.values_mut() {
data.desired = AppStatus::Installed;
// TODO: Installing app in one deployment should not fail the whole install process for all deployments
if let Some(id) = &data.id {
if !data.deployment.is_app_installed(id.clone()).await? {
data.id = Some(data.deployment.install_app(manifest.as_ref()).await?);
}
}
}
}
}
Ok(())
}

pub async fn uninstall(&mut self) -> Result<()> {
for data in self.properties.values_mut() {
data.desired = AppStatus::NotInstalled;
// TODO: Uninstalling app in one deployment should not fail the whole uninstall process for all deployments
if let Some(id) = &data.id {
if data.deployment.is_app_installed(id.clone()).await? {
data.deployment.uninstall_app(id.clone()).await?;
data.id = None;
}
}
}
Ok(())
}

pub async fn create_instance(&mut self, instance_config: InstanceConfig) -> Result<()> {
for data in self.properties.values_mut() {
// TODO: Creating app in one deployment should not fail the whole creation process for all deployments
let id = data
.deployment
.create_instance(instance_config.clone())
.await?;
data.instances.insert(
id.clone(),
Instance::new(
id,
instance_config.clone(),
data.deployment.clone(),
InstanceStatus::Created,
),
);
}
Ok(())
}
}
11 changes: 11 additions & 0 deletions flecs-core/src/jeweler/deployment.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use crate::jeweler::app::AppDeployment;
use crate::jeweler::instance::InstanceDeployment;
use crate::jeweler::network::NetworkDeployment;
use async_trait::async_trait;

pub type DeploymentId = String;

#[async_trait]
pub trait Deployment: Send + Sync + AppDeployment + InstanceDeployment + NetworkDeployment {
async fn id(&self) -> DeploymentId;
}
147 changes: 147 additions & 0 deletions flecs-core/src/jeweler/instance.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
use super::Result;
use crate::jeweler::deployment::Deployment;
use crate::jeweler::volume::VolumeDeployment;
use async_trait::async_trait;
use std::collections::HashMap;
use std::path::Path;
use std::sync::Arc;

#[async_trait]
pub trait InstanceDeployment: VolumeDeployment {
async fn create_instance(&self, config: InstanceConfig) -> Result<InstanceId>;
async fn delete_instance(&self, id: InstanceId) -> Result<()>;
async fn start_instance(&self, id: InstanceId) -> Result<()>;
async fn stop_instance(&self, id: InstanceId) -> Result<()>;
async fn ready_instance(&self, id: InstanceId) -> Result<()>;
async fn import_instance(&self, path: &Path) -> Result<InstanceId>;
async fn export_instance(&self, id: InstanceId, path: &Path) -> Result<()> {
let config = self.instance_config(id.clone()).await?;
self.export_config(config, path).await?;
self.export_volumes(id, path).await?;
Ok(())
}
async fn export_config(&self, config: InstanceConfig, path: &Path) -> Result<()>;
async fn instance_status(&self, id: InstanceId) -> Result<InstanceStatus>;
async fn instance_config(&self, id: InstanceId) -> Result<InstanceConfig>;
async fn instance(&self, id: InstanceId) -> Result<(InstanceConfig, InstanceStatus)> {
Ok((
self.instance_config(id.clone()).await?,
self.instance_status(id).await?,
))
}
async fn instances(&self) -> Result<HashMap<InstanceId, (InstanceConfig, InstanceStatus)>>;
async fn export_instances(&self, path: &Path) -> Result<()> {
for id in self.instances().await?.keys() {
self.export_instance(id.clone(), path).await?;
}
Ok(())
}
async fn copy_from_instance(&self, id: InstanceId, src: &Path, dst: &Path) -> Result<()>;
async fn copy_to_instance(&self, id: InstanceId, src: &Path, dst: &Path) -> Result<()>;
// TODO: Maybe move function to enum InstanceStatus
async fn is_instance_runnable(&self, id: InstanceId) -> Result<bool> {
Ok(self.instance_status(id).await? == InstanceStatus::Created)
}
// TODO: Maybe move function to enum InstanceStatus
async fn is_instance_running(&self, id: InstanceId) -> Result<bool> {
Ok(self.instance_status(id).await? == InstanceStatus::Running)
}
}

pub(crate) type InstanceId = String;
#[derive(Default, Clone)]
pub struct InstanceConfig {
// TBD
}

#[derive(Debug, PartialEq)]
pub enum InstanceStatus {
// TBD
NotCreated,
Requested,
ResourcesReady,
Created,
Stopped,
Running,
Orphaned,
Unknown,
}

pub struct Instance {
id: InstanceId,
pub config: InstanceConfig,
deployment: Arc<dyn Deployment>,
desired: InstanceStatus,
}

impl Instance {
pub(super) fn new(
id: InstanceId,
config: InstanceConfig,
deployment: Arc<dyn Deployment>,
desired: InstanceStatus,
) -> Self {
Self {
id,
config,
deployment,
desired,
}
}

pub async fn start(&mut self) -> Result<()> {
self.desired = InstanceStatus::Running;
match self.deployment.instance_status(self.id.clone()).await? {
InstanceStatus::Running => Ok(()),
_ => self.deployment.start_instance(self.id.clone()).await,
}
}

pub async fn stop(&mut self) -> Result<()> {
self.desired = InstanceStatus::Stopped;
match self.deployment.instance_status(self.id.clone()).await? {
InstanceStatus::Stopped => Ok(()),
_ => self.deployment.stop_instance(self.id.clone()).await,
}
}

pub async fn delete(self) -> Result<(), (anyhow::Error, Self)> {
self.deployment
.delete_instance(self.id.clone())
.await
.map_err(|e| (e, self))
}

pub async fn ready(&mut self) -> Result<()> {
// TODO: Check status, error handling
self.deployment.ready_instance(self.id.clone()).await
}

pub async fn export(&self, path: &Path) -> Result<()> {
self.deployment.export_instance(self.id.clone(), path).await
}

pub async fn status(&self) -> Result<InstanceStatus> {
self.deployment.instance_status(self.id.clone()).await
}

pub async fn copy_from(&self, src: &Path, dst: &Path) -> Result<()> {
self.deployment
.copy_from_instance(self.id.clone(), src, dst)
.await
}

pub async fn copy_to(&self, src: &Path, dst: &Path) -> Result<()> {
self.deployment
.copy_to_instance(self.id.clone(), src, dst)
.await
}

pub async fn is_runnable(&self) -> Result<bool> {
self.deployment.is_instance_runnable(self.id.clone()).await
}

pub async fn is_running(&self) -> Result<bool> {
self.deployment.is_instance_running(self.id.clone()).await
}
}
6 changes: 6 additions & 0 deletions flecs-core/src/jeweler/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pub mod app;
pub mod deployment;
pub mod instance;
pub mod network;
pub mod volume;
pub use super::Result;
23 changes: 23 additions & 0 deletions flecs-core/src/jeweler/network.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use super::Result;
use async_trait::async_trait;
use std::collections::HashMap;
use std::net::IpAddr;

pub type NetworkId = String;
pub struct Network {
// TBD
}
#[derive(Default)]
pub struct NetworkConfig {
// TBD
}

#[async_trait]
pub trait NetworkDeployment {
async fn create_network(&self, config: NetworkConfig) -> Result<NetworkId>;
async fn delete_network(&self, id: NetworkId) -> Result<()>;
async fn network(&self, id: NetworkId) -> Result<Network>;
async fn networks(&self) -> Result<HashMap<NetworkId, Network>>;
async fn connect_network(&self, id: NetworkId, address: IpAddr) -> Result<()>;
async fn disconnect_network(&self, id: NetworkId, address: IpAddr) -> Result<()>;
}
27 changes: 27 additions & 0 deletions flecs-core/src/jeweler/volume.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use super::instance::InstanceId;
use super::Result;
use async_trait::async_trait;
use std::collections::HashMap;
use std::path::Path;

type VolumeId = String;
#[derive(Default)]
pub struct VolumeConfig {
// TBD
}

#[async_trait]
pub trait VolumeDeployment {
async fn create_volume(&self, config: VolumeConfig) -> Result<VolumeId>;
async fn delete_volume(&self, id: VolumeId) -> Result<()>;
async fn import_volume(&self, path: &Path) -> Result<VolumeId>;
async fn export_volume(&self, id: VolumeId, path: &Path) -> Result<()>; // TODO: Arguments, return type
async fn volumes(&self, instance_id: InstanceId) -> Result<HashMap<VolumeId, VolumeConfig>>;
async fn export_volumes(&self, instance_id: InstanceId, path: &Path) -> Result<()> {
// TODO: more logic
for volume_id in self.volumes(instance_id).await?.keys() {
self.export_volume(volume_id.clone(), path).await?;
}
Ok(())
}
}
2 changes: 2 additions & 0 deletions flecs-core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod cellar;
mod flecs_rest;
pub mod fsm;
pub mod jeweler;
pub mod lore;
pub mod quest;
pub mod relic;
Expand All @@ -9,3 +10,4 @@ pub mod vault;

pub use anyhow::Error;
pub use anyhow::Result;
// TODO: Unify structs (App, Instance, Deployment, ...) with structs from Pouches and move them there

0 comments on commit ba256a8

Please # to comment.