|
6 | 6 | use std::sync::Arc; |
7 | 7 | use std::time::Duration; |
8 | 8 |
|
9 | | -use anyhow::{Result, bail}; |
| 9 | +use anyhow::Result; |
10 | 10 | use env_logger::Env; |
11 | 11 | use futures_util::StreamExt; |
12 | 12 | use kube::runtime::{ |
13 | 13 | controller::{Action, Controller}, |
14 | 14 | watcher, |
15 | 15 | }; |
16 | | -use kube::{Api, Client, api::ListParams}; |
17 | | - |
18 | | -use log::{error, info}; |
19 | | -use thiserror::Error; |
| 16 | +use kube::{Api, Client}; |
| 17 | +use log::{error, info, warn}; |
20 | 18 |
|
21 | 19 | use crds::ConfidentialCluster; |
22 | 20 | mod reference_values; |
23 | 21 | mod trustee; |
24 | 22 |
|
25 | | -#[derive(Debug, Error)] |
26 | | -enum Error {} |
27 | | - |
28 | | -#[derive(Clone)] |
29 | | -struct ContextData { |
30 | | - #[allow(dead_code)] |
31 | | - client: Client, |
32 | | -} |
33 | | - |
34 | 23 | const BOOT_IMAGE: &str = "quay.io/fedora/fedora-coreos:42.20250705.3.0"; |
35 | 24 |
|
36 | | -async fn list_confidential_clusters(client: Client) -> anyhow::Result<ConfidentialCluster> { |
37 | | - info!( |
38 | | - "Listing ConfidentialClusters in namespace '{}'", |
39 | | - client.default_namespace() |
40 | | - ); |
41 | | - let api: Api<ConfidentialCluster> = Api::default_namespaced(client.clone()); |
42 | | - let lp = ListParams::default(); |
43 | | - let list = api.list(&lp).await?; |
44 | | - match list.items.len() { |
45 | | - 0 => bail!("No confidential cluster resource found"), |
46 | | - 1 => { |
47 | | - let item = &list.items[0]; |
48 | | - info!( |
49 | | - "Found ConfidentialCluster: {}", |
50 | | - item.metadata.name.as_deref().unwrap_or("<no name>"), |
51 | | - ); |
52 | | - Ok(item.clone()) |
53 | | - } |
54 | | - _ => bail!("too many confidential cluster resources defined in the namespace"), |
| 25 | +async fn reconcile( |
| 26 | + cocl: Arc<ConfidentialCluster>, |
| 27 | + client: Arc<Client>, |
| 28 | +) -> Result<Action, operator::ControllerError> { |
| 29 | + let name = cocl.metadata.name.as_deref().unwrap_or("<no name>"); |
| 30 | + if cocl.metadata.deletion_timestamp.is_some() { |
| 31 | + info!("Registered deletion of ConfidentialCluster {name}"); |
| 32 | + return Ok(Action::await_change()); |
| 33 | + } |
| 34 | + let kube_client = Arc::unwrap_or_clone(client); |
| 35 | + |
| 36 | + let cocls: Api<ConfidentialCluster> = Api::default_namespaced(kube_client.clone()); |
| 37 | + let list = cocls.list(&Default::default()).await; |
| 38 | + let cocl_list = list.map_err(Into::<anyhow::Error>::into)?; |
| 39 | + if cocl_list.items.len() > 1 { |
| 40 | + let namespace = kube_client.default_namespace(); |
| 41 | + warn!( |
| 42 | + "More than one ConfidentialCluster found in namespace {namespace}. \ |
| 43 | + cocl-operator does not support more than one ConfidentialCluster. Requeueing...", |
| 44 | + ); |
| 45 | + return Ok(Action::requeue(Duration::from_secs(60))); |
55 | 46 | } |
56 | | -} |
57 | 47 |
|
58 | | -async fn reconcile(_g: Arc<ConfidentialCluster>, _ctx: Arc<ContextData>) -> Result<Action, Error> { |
59 | | - Ok(Action::requeue(Duration::from_secs(300))) |
| 48 | + info!("Setting up ConfidentialCluster {name}"); |
| 49 | + install_trustee_configuration(kube_client, &cocl).await?; |
| 50 | + Ok(Action::await_change()) |
60 | 51 | } |
61 | 52 |
|
62 | | -async fn install_trustee_configuration(client: Client) -> Result<()> { |
63 | | - let cocl = list_confidential_clusters(client.clone()).await?; |
| 53 | +async fn install_trustee_configuration(client: Client, cocl: &ConfidentialCluster) -> Result<()> { |
64 | 54 | let trustee_namespace = cocl.spec.trustee.namespace.clone(); |
65 | 55 |
|
66 | 56 | match trustee::generate_kbs_auth_public_key( |
@@ -99,7 +89,7 @@ async fn install_trustee_configuration(client: Client) -> Result<()> { |
99 | 89 | let rv_ctx = operator::RvContextData { |
100 | 90 | client: client.clone(), |
101 | 91 | trustee_namespace: trustee_namespace.clone(), |
102 | | - pcrs_compute_image: cocl.spec.pcrs_compute_image, |
| 92 | + pcrs_compute_image: cocl.spec.pcrs_compute_image.clone(), |
103 | 93 | rv_map: cocl.spec.trustee.reference_values.clone(), |
104 | 94 | }; |
105 | 95 | reference_values::launch_rv_job_controller(rv_ctx.clone()).await; |
@@ -185,22 +175,14 @@ async fn install_trustee_configuration(client: Client) -> Result<()> { |
185 | 175 | async fn main() -> Result<()> { |
186 | 176 | env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); |
187 | 177 |
|
188 | | - let client = Client::try_default().await?; |
189 | | - let context = Arc::new(ContextData { |
190 | | - client: client.clone(), |
191 | | - }); |
| 178 | + let kube_client = Client::try_default().await?; |
192 | 179 | info!("Confidential clusters operator",); |
193 | | - let cl = Api::<ConfidentialCluster>::default_namespaced(client.clone()); |
| 180 | + let cl = Api::<ConfidentialCluster>::default_namespaced(kube_client.clone()); |
194 | 181 |
|
195 | | - tokio::spawn(install_trustee_configuration(client.clone())); |
| 182 | + let client = Arc::new(kube_client); |
196 | 183 | Controller::new(cl, watcher::Config::default()) |
197 | | - .run::<_, ContextData>(reconcile, operator::controller_error_policy, context) |
198 | | - .for_each(|res| async move { |
199 | | - match res { |
200 | | - Ok(o) => info!("reconciled {o:?}"), |
201 | | - Err(e) => info!("reconcile failed: {e:?}"), |
202 | | - } |
203 | | - }) |
| 184 | + .run::<_, Client>(reconcile, operator::controller_error_policy, client) |
| 185 | + .for_each(operator::controller_info) |
204 | 186 | .await; |
205 | 187 |
|
206 | 188 | Ok(()) |
|
0 commit comments