async fn reconcile(
    trade: TradeSecret,
    ctx: Context<Ctx>,
) -> Result<ReconcilerAction, ReconcilerError> {
    // eprintln!("TradeSecret: {:?}", trade);

    // The namespace the TradeSecret is in is the namespace the secrets are in
    let namespace: &str = &trade
        .metadata
        .namespace
        .as_ref()
        .expect("TradeSecrets should always be namespaced");

    eprintln!("Updating {}.{}", namespace, trade.metadata.name.unwrap());

    let secrets: Api<Secret> = Api::namespaced(ctx.get_ref().client().clone(), namespace);

    let source_secret = secrets
        .get(&trade.spec.source)
        .await
        .map_err(|_| ReconcilerError::SecretNotFound)?;

    let dest_secret = secrets
        .get(&trade.spec.destination)
        .await
        .map_err(|_| ReconcilerError::SecretNotFound)?;

    match trade.spec.strategy {
        // Simple copy of a field from source to dest
        PatchStrategy::Copy { ref items } => {
            // Compile a hashmap of all the source values we care about.
            // If any are missing, raise an error
            let source_values: HashMap<String, ByteString> = items
                .iter()
                .map(|item| {
                    source_secret
                        .data
                        .as_ref()
                        .and_then(|data| {
                            data.get(&item.source)
                                .map(|value| (item.source.clone(), value.clone()))
                        })
                        .ok_or(ReconcilerError::SourceFieldMissing)
                })
                .collect::<Result<HashMap<_, _>, ReconcilerError>>()?;

            // Compile a hashmap of Options of all the dest values we care about.
            let dest_values: HashMap<String, Option<ByteString>> = items
                .iter()
                .map(|item| {
                    dest_secret
                        .data
                        .as_ref()
                        .and_then(|data| {
                            data.get(&item.destination)
                                .map(|value| (item.destination.clone(), Some(value.clone())))
                        })
                        .unwrap_or_else(|| (item.destination.clone(), None))
                })
                .collect();

            // Compile a hashmap of all the changes that need to be applied
            let updates: HashMap<&str, &ByteString> = items
                .iter()
                .filter_map(|item| {
                    let source_value = source_values
                        .get(&item.source)
                        .expect("source key should exist");

                    let dest_value = dest_values
                        .get(&item.destination)
                        .expect("dest key should atleast be None")
                        .as_ref();

                    if dest_value.is_none() || *source_value != *dest_value.unwrap() {
                        Some((item.destination.as_ref(), source_value))
                    } else {
                        None
                    }
                })
                .collect();

            // If there's no changes to apply, we're done
            if updates.is_empty() {
                eprintln!("Destination already matches source. No updates needed.");
                return Ok(ctx.get_ref().requeue_action());
            }

            // Create the patch from the changes
            let patch = serde_json::to_vec(&serde_json::json!({ "data": updates }))
                .map_err(|_| ReconcilerError::Unknown)?;

            eprintln!(
                "Updating secret '{}': {}",
                trade.spec.destination,
                std::str::from_utf8(&patch).map_err(|_| ReconcilerError::Unknown)?,
            );

            // Apply the patch in strategic merge mode
            secrets
                .patch(&trade.spec.destination, &Default::default(), patch)
                .await
                .map_err(|e| {
                    eprintln!("Error {}: {:?}", e, e);
                    ReconcilerError::Unknown
                })?;
        }
    };

    Ok(ctx.get_ref().requeue_action())
}
/// The core of the controller.
///
/// Takes a trade secret
/// Performs updates, if necessary.
/// Requeues the trade secret for processing again in 5 minutes
The core of the controller.
Takes a trade secret
Performs updates, if necessary.
Requeues the trade secret for processing again in 5 minutes
The core of the controller . Takes a trade secret Performs updates if necessary . Requeues the trade secret for processing again in 5 minutes
async fn reconcile(
    trade: TradeSecret,
    ctx: Context<Ctx>,
) -> Result<ReconcilerAction, ReconcilerError> {
    // eprintln!("TradeSecret: {:?}", trade);
    // The namespace the TradeSecret is in is the namespace the secrets are in
    let namespace: &str = &trade
        .metadata
        .namespace
        .as_ref()
        .expect("TradeSecrets should always be namespaced");
    eprintln!("Updating {}.{}", namespace, trade.metadata.name.unwrap());
    let secrets: Api<Secret> = Api::namespaced(ctx.get_ref().client().clone(), namespace);
    let source_secret = secrets
        .get(&trade.spec.source)
        .await
        .map_err(|_| ReconcilerError::SecretNotFound)?;
    let dest_secret = secrets
        .get(&trade.spec.destination)
        .await
        .map_err(|_| ReconcilerError::SecretNotFound)?;
    match trade.spec.strategy {
        // Simple copy of a field from source to dest
        PatchStrategy::Copy { ref items } => {
            // Compile a hashmap of all the source values we care about.
            // If any are missing, raise an error
            let source_values: HashMap<String, ByteString> = items
                .iter()
                .map(|item| {
                    source_secret
                        .data
                        .as_ref()
                        .and_then(|data| {
                            data.get(&item.source)
                                .map(|value| (item.source.clone(), value.clone()))
                        })
                        .ok_or(ReconcilerError::SourceFieldMissing)
                })
                .collect::<Result<HashMap<_, _>, ReconcilerError>>()?;
            // Compile a hashmap of Options of all the dest values we care about.
            let dest_values: HashMap<String, Option<ByteString>> = items
                .iter()
                .map(|item| {
                    dest_secret
                        .data
                        .as_ref()
                        .and_then(|data| {
                            data.get(&item.destination)
                                .map(|value| (item.destination.clone(), Some(value.clone())))
                        })
                        .unwrap_or_else(|| (item.destination.clone(), None))
                })
                .collect();
            // Compile a hashmap of all the changes that need to be applied
            let updates: HashMap<&str, &ByteString> = items
                .iter()
                .filter_map(|item| {
                    let source_value = source_values
                        .get(&item.source)
                        .expect("source key should exist");
                    let dest_value = dest_values
                        .get(&item.destination)
                        .expect("dest key should atleast be None")
                        .as_ref();
                    if dest_value.is_none() || *source_value != *dest_value.unwrap() {
                        Some((item.destination.as_ref(), source_value))
                    } else {
                        None
                    }
                })
                .collect();
            // If there's no changes to apply, we're done
            if updates.is_empty() {
                eprintln!("Destination already matches source. No updates needed.");
                return Ok(ctx.get_ref().requeue_action());
            }
            // Create the patch from the changes
            let patch = serde_json::to_vec(&serde_json::json!({ "data": updates }))
                .map_err(|_| ReconcilerError::Unknown)?;
            eprintln!(
                "Updating secret '{}': {}",
                trade.spec.destination,
                std::str::from_utf8(&patch).map_err(|_| ReconcilerError::Unknown)?,
            );
            // Apply the patch in strategic merge mode
            secrets
                .patch(&trade.spec.destination, &Default::default(), patch)
                .await
                .map_err(|e| {
                    eprintln!("Error {}: {:?}", e, e);
                    ReconcilerError::Unknown
                })?;
        }
    };
    Ok(ctx.get_ref().requeue_action())
}
async fn reconcile ( trade : TradeSecret , ctx : Context < Ctx > , ) -> Result < ReconcilerAction , ReconcilerError > { // eprintln!("TradeSecret: {:?}", trade); // The namespace the TradeSecret is in is the namespace the secrets are in let namespace : & str = & trade . metadata . namespace . as_ref ( ) . expect ( " " ) ; eprintln ! ( " " namespace trade metadata name unwrap ( ) ) ; let secrets : Api < Secret > = Api :: namespaced ( ctx . get_ref ( ) . client ( ) . clone ( ) , namespace ) ; let source_secret = secrets . get ( & trade . spec . source ) . await . map_err ( | _ | ReconcilerError :: SecretNotFound ) ? ; let dest_secret = secrets . get ( & trade . spec . destination ) . await . map_err ( | _ | ReconcilerError :: SecretNotFound ) ? ; match trade . spec . strategy { // Simple copy of a field from source to dest PatchStrategy :: Copy { ref items } => { // Compile a hashmap of all the source values we care about. // If any are missing, raise an error let source_values : HashMap < String , ByteString > = items . iter ( ) . map ( | item | { source_secret . data . as_ref ( ) . and_then ( | data | { data . get ( & item . source ) . map ( | value | ( item . source . clone ( ) , value . clone ( ) ) ) } ) . ok_or ( ReconcilerError :: SourceFieldMissing ) } ) . collect :: < Result < HashMap < _ , _ > , ReconcilerError > > ( ) ? ; // Compile a hashmap of Options of all the dest values we care about. let dest_values : HashMap < String , Option < ByteString > > = items . iter ( ) . map ( | item | { dest_secret . data . as_ref ( ) . and_then ( | data | { data . get ( & item . destination ) . map ( | value | ( item . destination . clone ( ) , Some ( value . clone ( ) ) ) ) } ) . unwrap_or_else ( | | ( item . destination . clone ( ) , None ) ) } ) . collect ( ) ; // Compile a hashmap of all the changes that need to be applied let updates : HashMap < & str , & ByteString > = items . iter ( ) . filter_map ( | item | { let source_value = source_values . get ( & item . source ) . expect ( " " ) ; let dest_value = dest_values . get ( & item . destination ) . expect ( " " ) . as_ref ( ) ; if dest_value . is_none ( ) || * source_value != * dest_value . unwrap ( ) { Some ( ( item . destination . as_ref ( ) , source_value ) ) } else { None } } ) . collect ( ) ; // If there's no changes to apply, we're done if updates . is_empty ( ) { eprintln ! ( " " ) ; return Ok ( ctx . get_ref ( ) . requeue_action ( ) ) ; } // Create the patch from the changes let patch = serde_json :: to_vec ( & serde_json :: json ! ( { " " updates } ) ) . map_err ( | _ | ReconcilerError :: Unknown ) ? ; eprintln ! ( " " trade spec destination std str from_utf8 ( patch ) map_err ( ReconcilerError Unknown ) ) ; // Apply the patch in strategic merge mode secrets . patch ( & trade . spec . destination , & Default :: default ( ) , patch ) . await . map_err ( | e | { eprintln ! ( " " e e ) ; ReconcilerError :: Unknown } ) ? ; } } ; Ok ( ctx . get_ref ( ) . requeue_action ( ) ) }
The core of the controller.
The core of the controller .
trade
TradeSecret
ctx
Context<Ctx>