edgehog_device_runtime_containers/resource/
mod.rs1use std::future::Future;
24
25use async_trait::async_trait;
26use tracing::debug;
27use uuid::Uuid;
28
29use crate::{
30 error::DockerError,
31 properties::{Client, PropertyError},
32 store::{StateStore, StoreError},
33 Docker,
34};
35
36pub(crate) mod container;
37pub(crate) mod deployment;
38pub(crate) mod device_mapping;
39pub(crate) mod image;
40pub(crate) mod network;
41pub(crate) mod volume;
42
43#[derive(Debug, thiserror::Error, displaydoc::Display)]
45pub enum ResourceError {
46 Property(#[from] PropertyError),
48 Store(#[from] StoreError),
50 Docker(#[source] DockerError),
52 Missing {
54 id: Uuid,
56 resource: &'static str,
58 },
59}
60
61#[derive(Debug)]
62pub(crate) struct Context<'a, D> {
63 pub(crate) id: Uuid,
65 pub(crate) store: &'a mut StateStore,
66 pub(crate) device: &'a mut D,
67 pub(crate) client: &'a Docker,
68}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq)]
72pub(crate) enum State {
73 Missing,
75 Created,
77}
78
79impl<T> From<T> for ResourceError
80where
81 T: Into<DockerError>,
82{
83 fn from(value: T) -> Self {
84 ResourceError::Docker(value.into())
85 }
86}
87
88type Result<T> = std::result::Result<T, ResourceError>;
89
90#[async_trait]
91pub(crate) trait Resource<D>: Sized
92where
93 D: Client + Sync + 'static,
94{
95 async fn publish(ctx: Context<'_, D>) -> Result<()>;
96}
97
98pub(crate) trait Create<D>: Resource<D>
99where
100 D: Client + Send + Sync + 'static,
101{
102 fn fetch(ctx: &mut Context<'_, D>) -> impl Future<Output = Result<(State, Self)>> + Send;
103
104 fn create(&mut self, ctx: &mut Context<'_, D>) -> impl Future<Output = Result<()>> + Send;
105
106 fn delete(&mut self, ctx: &mut Context<'_, D>) -> impl Future<Output = Result<()>> + Send;
107
108 fn unset(&mut self, ctx: &mut Context<'_, D>) -> impl Future<Output = Result<()>> + Send;
109
110 fn refresh(ctx: &mut Context<'_, D>) -> impl Future<Output = Result<()>> + Send;
111
112 async fn up(mut ctx: Context<'_, D>) -> Result<Self> {
113 let (state, mut resource) = Self::fetch(&mut ctx).await?;
114
115 match state {
116 State::Missing => {
117 debug!("resource missing, creating it");
118
119 resource.create(&mut ctx).await?;
120 }
121 State::Created => {
122 debug!("resource already created");
123 }
124 }
125
126 Ok(resource)
127 }
128
129 async fn down(mut ctx: Context<'_, D>) -> Result<()> {
130 let (state, mut resource) = Self::fetch(&mut ctx).await?;
131
132 match state {
133 State::Missing => {
134 debug!("resource already missing");
135 }
136 State::Created => {
137 debug!("resource found, deleting it");
138
139 resource.delete(&mut ctx).await?
140 }
141 }
142
143 resource.unset(&mut ctx).await?;
144
145 Ok(())
146 }
147}