staircase 0.0.7

Kubernetes Step-based Operator
Documentation
use std::{fmt::Debug, marker::PhantomData, time::Duration};

use kube::{ResourceExt, api::PostParams};
use staircase::{
    controller::{Mutable, MutableStepOutcome, MutableStepResult, RunContext, Step},
    resources::{ApiResource, ComponentizedResource, NamedResource, ResourceGenerator},
    util::get_opt_by_name,
};

use crate::{
    crd::Elevator,
    r#gen::{DATA_INDEX_HTML, FLOOR_FILE},
    graphics::{elevator_ascii, html_body},
    resources::ElevatorPage,
    steps::StepError,
};

#[derive(Default)]
pub struct CreateResource<T> {
    _dummy: PhantomData<T>,
}
pub struct UpdateConfigmap {}

impl<T> Step for CreateResource<T>
where
    T: ComponentizedResource + Sync,
    T::Resource: serde::Serialize + Send + Sync,
    Elevator: ApiResource<T>,
    Elevator: ResourceGenerator<T, GenConfig: Default, Error: Debug>,
    Elevator: NamedResource<T>,
{
    type Error = StepError;
    type InData = ();
    type Mode = Mutable;
    type OutData = ();
    type Resource = Elevator;

    async fn run(
        &self,
        context: &RunContext<Self::Resource>,
        data: Self::InData,
    ) -> MutableStepResult<Self::Resource, Self::OutData, Self::Error> {
        if get_opt_by_name::<_, T>(context.resource.as_ref(), &context.client)
            .await?
            .is_none()
        {
            let res = ResourceGenerator::<T>::generate(context.resource.as_ref(), Default::default()).unwrap();
            let api = ApiResource::<T>::api(context.resource.as_ref(), context.client.clone());
            api.create(&PostParams::default(), &res).await?;
            Ok(MutableStepOutcome::Modified { status: None })
        } else {
            Ok(MutableStepOutcome::NoModification { data })
        }
    }
}

impl Step for UpdateConfigmap {
    type Error = StepError;
    type InData = ();
    type Mode = Mutable;
    type OutData = ();
    type Resource = Elevator;

    async fn run(
        &self,
        context: &RunContext<Self::Resource>,
        data: Self::InData,
    ) -> MutableStepResult<Self::Resource, Self::OutData, Self::Error> {
        match get_opt_by_name::<_, ElevatorPage>(context.resource.as_ref(), &context.client).await? {
            Some(mut configmap) => {
                let cdata = configmap.data.as_mut().expect("data should exist always");
                let floor_cnt = cdata.get(FLOOR_FILE).expect("floor file should exist always");
                let floor: i8 = floor_cnt.parse::<i8>().unwrap_or(0);

                if floor != context.resource.spec.floor {
                    // dont to it immeadiatly ugly hack :)
                    tokio::time::sleep(Duration::from_millis(2000)).await;

                    let new_floor = if context.resource.spec.floor > floor {
                        floor + 1
                    } else {
                        floor - 1
                    };

                    let page = html_body(&elevator_ascii(-2, 10, new_floor, &context.resource.spec.content));

                    {
                        let data_index = cdata.get_mut(DATA_INDEX_HTML).expect("index.html should exist always");
                        *data_index = page;
                    }
                    {
                        let floor_cnt = cdata.get_mut(FLOOR_FILE).expect("floor file should exist always");
                        *floor_cnt = new_floor.to_string();
                    }

                    let api = ApiResource::<ElevatorPage>::api(context.resource.as_ref(), context.client.clone());
                    api.replace(&configmap.name_any(), &PostParams::default(), &configmap)
                        .await?;
                    Ok(MutableStepOutcome::Modified { status: None })
                } else {
                    Ok(MutableStepOutcome::NoModification { data })
                }
            },
            None => {
                let res = ResourceGenerator::<ElevatorPage>::generate(context.resource.as_ref(), ()).unwrap();
                let api = ApiResource::<ElevatorPage>::api(context.resource.as_ref(), context.client.clone());
                api.create(&PostParams::default(), &res).await?;
                Ok(MutableStepOutcome::Modified { status: None })
            },
        }
    }
}