mid coding commit
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use color_eyre::eyre::eyre;
|
||||
use emver::VersionRange;
|
||||
use futures::{Future, FutureExt};
|
||||
use indexmap::IndexMap;
|
||||
use models::ImageId;
|
||||
use patch_db::HasModel;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::context::RpcContext;
|
||||
use crate::prelude::*;
|
||||
use crate::procedure::docker::DockerContainers;
|
||||
use crate::procedure::{PackageProcedure, ProcedureName};
|
||||
use crate::s9pk::manifest::PackageId;
|
||||
use crate::util::Version;
|
||||
use crate::volume::Volumes;
|
||||
use crate::{Error, ResultExt};
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize, HasModel)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
#[model = "Model<Self>"]
|
||||
pub struct Migrations {
|
||||
pub from: IndexMap<VersionRange, PackageProcedure>,
|
||||
pub to: IndexMap<VersionRange, PackageProcedure>,
|
||||
}
|
||||
impl Migrations {
|
||||
#[instrument(skip_all)]
|
||||
pub fn validate(
|
||||
&self,
|
||||
_container: &Option<DockerContainers>,
|
||||
eos_version: &Version,
|
||||
volumes: &Volumes,
|
||||
image_ids: &BTreeSet<ImageId>,
|
||||
) -> Result<(), Error> {
|
||||
for (version, migration) in &self.from {
|
||||
migration
|
||||
.validate(eos_version, volumes, image_ids, true)
|
||||
.with_ctx(|_| {
|
||||
(
|
||||
crate::ErrorKind::ValidateS9pk,
|
||||
format!("Migration from {}", version),
|
||||
)
|
||||
})?;
|
||||
}
|
||||
for (version, migration) in &self.to {
|
||||
migration
|
||||
.validate(eos_version, volumes, image_ids, true)
|
||||
.with_ctx(|_| {
|
||||
(
|
||||
crate::ErrorKind::ValidateS9pk,
|
||||
format!("Migration to {}", version),
|
||||
)
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub fn from<'a>(
|
||||
&'a self,
|
||||
_container: &'a Option<DockerContainers>,
|
||||
ctx: &'a RpcContext,
|
||||
version: &'a Version,
|
||||
pkg_id: &'a PackageId,
|
||||
pkg_version: &'a Version,
|
||||
volumes: &'a Volumes,
|
||||
) -> Option<impl Future<Output = Result<MigrationRes, Error>> + 'a> {
|
||||
if let Some((_, migration)) = self
|
||||
.from
|
||||
.iter()
|
||||
.find(|(range, _)| version.satisfies(*range))
|
||||
{
|
||||
Some(async move {
|
||||
migration
|
||||
.execute(
|
||||
ctx,
|
||||
pkg_id,
|
||||
pkg_version,
|
||||
ProcedureName::Migration, // Migrations cannot be executed concurrently
|
||||
volumes,
|
||||
Some(version),
|
||||
None,
|
||||
)
|
||||
.map(|r| {
|
||||
r.and_then(|r| {
|
||||
r.map_err(|e| {
|
||||
Error::new(eyre!("{}", e.1), crate::ErrorKind::MigrationFailed)
|
||||
})
|
||||
})
|
||||
})
|
||||
.await
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub fn to<'a>(
|
||||
&'a self,
|
||||
ctx: &'a RpcContext,
|
||||
version: &'a Version,
|
||||
pkg_id: &'a PackageId,
|
||||
pkg_version: &'a Version,
|
||||
volumes: &'a Volumes,
|
||||
) -> Option<impl Future<Output = Result<MigrationRes, Error>> + 'a> {
|
||||
if let Some((_, migration)) = self.to.iter().find(|(range, _)| version.satisfies(*range)) {
|
||||
Some(async move {
|
||||
migration
|
||||
.execute(
|
||||
ctx,
|
||||
pkg_id,
|
||||
pkg_version,
|
||||
ProcedureName::Migration,
|
||||
volumes,
|
||||
Some(version),
|
||||
None,
|
||||
)
|
||||
.map(|r| {
|
||||
r.and_then(|r| {
|
||||
r.map_err(|e| {
|
||||
Error::new(eyre!("{}", e.1), crate::ErrorKind::MigrationFailed)
|
||||
})
|
||||
})
|
||||
})
|
||||
.await
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize, HasModel)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
#[model = "Model<Self>"]
|
||||
pub struct MigrationRes {
|
||||
pub configured: bool,
|
||||
}
|
||||
Reference in New Issue
Block a user