diff --git a/charts/tembo-operator/Chart.yaml b/charts/tembo-operator/Chart.yaml index fcdc6e31a..e9b22f668 100644 --- a/charts/tembo-operator/Chart.yaml +++ b/charts/tembo-operator/Chart.yaml @@ -3,7 +3,7 @@ name: tembo-operator description: 'Helm chart to deploy the tembo-operator' type: application icon: https://cloud.tembo.io/images/TemboElephant.png -version: 0.2.4 +version: 0.2.5 home: https://tembo.io sources: - https://github.com/tembo-io/tembo-stacks diff --git a/charts/tembo-operator/templates/crd.yaml b/charts/tembo-operator/templates/crd.yaml index f105a0ab1..fdacd3776 100644 --- a/charts/tembo-operator/templates/crd.yaml +++ b/charts/tembo-operator/templates/crd.yaml @@ -1591,7 +1591,7 @@ spec: nullable: true type: array image: - default: quay.io/tembo/standard-cnpg:15.3.0-1-0c19c7e + default: quay.io/tembo/standard-cnpg:15.3.0-1-3d9a853 description: |- The Postgres image to use for the CoreDB instance deployment. This should be a valid Postgres image that is compatible with the [https://tembo.io](https://tembo.io) platform. For more information please visit our [tembo-images](https://github.com/tembo-io/tembo-images) repository. diff --git a/conductor/Cargo.lock b/conductor/Cargo.lock index dd65b3c99..6ea39ed84 100644 --- a/conductor/Cargo.lock +++ b/conductor/Cargo.lock @@ -826,7 +826,7 @@ dependencies = [ [[package]] name = "controller" -version = "0.31.8" +version = "0.32.0" dependencies = [ "actix-web", "anyhow", diff --git a/conductor/src/lib.rs b/conductor/src/lib.rs index da5381664..317802326 100644 --- a/conductor/src/lib.rs +++ b/conductor/src/lib.rs @@ -136,10 +136,11 @@ pub async fn delete(client: Client, namespace: &str, name: &str) -> Result<(), C let coredb_api: Api = Api::namespaced(client, namespace); let params = DeleteParams::default(); info!("\nDeleting CoreDB: {}", name); - let _o = coredb_api + let _ = coredb_api .delete(name, ¶ms) .await .map_err(ConductorError::KubeError); + Ok(()) } @@ -189,6 +190,7 @@ pub async fn delete_namespace(client: Client, name: &str) -> Result<(), Conducto .delete(name, ¶ms) .await .map_err(ConductorError::KubeError); + Ok(()) } diff --git a/conductor/testdata/operator-values.yaml b/conductor/testdata/operator-values.yaml index 9f343591f..5997ea6e8 100644 --- a/conductor/testdata/operator-values.yaml +++ b/conductor/testdata/operator-values.yaml @@ -2,7 +2,7 @@ controller: image: tag: latest extraEnv: - - name: ENABLE_INITIAL_BACKUP + - name: ENABLE_BACKUP value: "false" - name: RUST_LOG value: info,kube=info,controller=info diff --git a/conductor/tests/integration_tests.rs b/conductor/tests/integration_tests.rs index a6714a68d..87bd8befb 100644 --- a/conductor/tests/integration_tests.rs +++ b/conductor/tests/integration_tests.rs @@ -10,7 +10,6 @@ #[cfg(test)] mod test { - use chrono::Utc; use k8s_openapi::{ api::{core::v1::Namespace, core::v1::PersistentVolumeClaim, core::v1::Pod}, apiextensions_apiserver::pkg::apis::apiextensions::v1::CustomResourceDefinition, @@ -22,10 +21,8 @@ mod test { }; use pgmq::{Message, PGMQueueExt}; - use conductor::{ - get_coredb_error_without_status, restart_coredb, - types::{self, StateToControlPlane}, - }; + use conductor::get_coredb_error_without_status; + use conductor::types::{self, StateToControlPlane}; use controller::extensions::types::{Extension, ExtensionInstallLocation}; use controller::{ apis::coredb_types::{CoreDB, CoreDBSpec}, @@ -154,7 +151,7 @@ mod test { image: "default-image-value".to_string() }) }); - let spec: CoreDBSpec = serde_json::from_value(spec_js).unwrap(); + let mut spec: CoreDBSpec = serde_json::from_value(spec_js).unwrap(); let msg = types::CRUDevent { organization_name: org_name.clone(), @@ -163,9 +160,11 @@ mod test { inst_id: "inst_02s4UKVbRy34SAYVSwZq2H".to_owned(), event_type: types::Event::Create, dbname: dbname.clone(), - spec: Some(spec), + spec: Some(spec.clone()), }; + // println!("Message: {:?}", msg); + let msg_id = queue.send(&myqueue, &msg).await; println!("Create msg_id: {msg_id:?}"); @@ -201,11 +200,11 @@ mod test { .await .expect("error deleting message"); - let spec = msg.message.spec.expect("No spec found in message"); + let passed_spec = msg.message.spec.expect("No spec found in message"); // assert that the message returned by Conductor includes the new metrics values in the spec - //println!("spec: {:?}", spec); - assert!(spec + // println!("spec: {:?}", passed_spec); + assert!(passed_spec .metrics .expect("no metrics in data-plane-event message") .queries @@ -214,10 +213,10 @@ mod test { .contains_key("pg_postmaster")); assert!( - !spec.extensions.is_empty(), + !passed_spec.extensions.is_empty(), "Extension object missing from spec" ); - let extensions = spec.extensions; + let extensions = passed_spec.extensions.clone(); assert!( !extensions.is_empty(), "Expected at least one extension: {:?}", @@ -234,7 +233,7 @@ mod test { // ADD AN EXTENSION - ASSERT IT MAKES IT TO STATUS.EXTENSIONS // conductor receives a CRUDevent from control plane // take note of number of extensions at this point in time - let mut extensions_add = extensions.clone(); + // let mut extensions_add = extensions.clone(); let _install_location = ExtensionInstallLocation::default(); let install_location = ExtensionInstallLocation { enabled: true, @@ -243,16 +242,13 @@ mod test { ..ExtensionInstallLocation::default() }; let install_location = install_location.clone(); - extensions_add.push(Extension { + spec.extensions.push(Extension { name: "pg_jsonschema".to_owned(), description: Some("fake description".to_string()), locations: vec![install_location], }); - let num_expected_extensions = extensions_add.len(); - let spec_js = serde_json::json!({ - "extensions": extensions_add, - }); - let spec: CoreDBSpec = serde_json::from_value(spec_js).unwrap(); + let num_expected_extensions = spec.extensions.len(); + // println!("Updated spec: {:?}", spec.clone()); let msg = types::CRUDevent { organization_name: org_name.clone(), data_plane_id: "org_02s3owPQskuGXHE8vYsGSY".to_owned(), @@ -260,7 +256,7 @@ mod test { inst_id: "inst_02s4UKVbRy34SAYVSwZq2H".to_owned(), event_type: types::Event::Update, dbname: dbname.clone(), - spec: Some(spec), + spec: Some(spec.clone()), }; let msg_id = queue.send(&myqueue, &msg).await; println!("Update msg_id: {msg_id:?}"); @@ -269,7 +265,7 @@ mod test { let mut extensions: Vec = vec![]; while num_expected_extensions != extensions.len() { let msg = get_dataplane_message(retries, retry_delay, &queue).await; - //println!("msg: {:?}", msg); + // println!("Update msg: {:?}", msg); queue .archive("myqueue_data_plane", msg.msg_id) .await @@ -284,10 +280,6 @@ mod test { // we added an extension, so it should be +1 now assert_eq!(num_expected_extensions, extensions.len()); - // Installing the new extensions will cause the pods to restart, but it can take a few - // seconds for that to happen. For now lets just wait and see if that fixes the problem. - thread::sleep(time::Duration::from_secs(40)); - pod_ready_and_running(pods.clone(), pod_name.clone()).await; // Get the last time the pod was started @@ -311,20 +303,28 @@ mod test { println!("start_time: {:?}", stdout); - // Once CNPG is running we want to restart - let cluster_name = namespace.clone(); + // Lets now test sending an Event::Restart to the queue and see if the + // pod restarts correctly. - restart_coredb(client.clone(), &namespace, &cluster_name, Utc::now()) - .await - .expect("failed restarting cnpg pod"); + let msg = types::CRUDevent { + organization_name: org_name.clone(), + data_plane_id: "org_02s3owPQskuGXHE8vYsGSY".to_owned(), + org_id: "org_02s3owPQskuGXHE8vYsGSY".to_owned(), + inst_id: "inst_02s4UKVbRy34SAYVSwZq2H".to_owned(), + event_type: types::Event::Restart, + dbname: dbname.clone(), + spec: Some(spec.clone()), + }; + let msg_id = queue.send(&myqueue, &msg).await; + println!("Restart msg_id: {:?}", msg_id); let mut is_ready = false; let mut current_iteration = 0; while !is_ready { if current_iteration > 30 { - panic!("CNPG pod did not restart after about 150 seconds"); + panic!("CNPG pod did not restart after about 300 seconds"); } - thread::sleep(time::Duration::from_secs(5)); + thread::sleep(time::Duration::from_secs(10)); let current_coredb = get_coredb_error_without_status(client.clone(), &namespace) .await .unwrap(); @@ -365,6 +365,7 @@ mod test { dbname: dbname.clone(), spec: None, }; + // println!("DELETE msg: {:?}", msg); let msg_id = queue.send(&myqueue, &msg).await; println!("Delete msg_id: {msg_id:?}"); @@ -395,26 +396,10 @@ mod test { let region = Region::new(aws_region); let aws_config_state = AWSConfigState::new(region.clone()).await; let stack_name = format!("org-{}-inst-{}-cf", org_name, dbname); - // let dcf = aws_config_state - // .delete_cloudformation_stack(&stack_name) - // .await; - // assert!(dcf); - // let exists = aws_config_state.does_stack_exist(&stack_name).await; - // assert!(!exists, "CF stack was not deleted"); - match aws_config_state - .delete_cloudformation_stack(&stack_name) - .await - { - Ok(_) => { - // If deletion was successful, check if the stack still exists - let stack_exists = aws_config_state.does_stack_exist(&stack_name).await; - assert!(!stack_exists, "CloudFormation stack was not deleted"); - } - Err(e) => { - // If there was an error deleting the stack, fail the test - panic!("Failed to delete CloudFormation stack: {:?}", e); - } - } + + // Check to see if the cloudformation stack exists + let cf_stack_deleted = check_cf_stack_deletion(&aws_config_state, &stack_name).await; + assert!(cf_stack_deleted, "CF stack was deleted"); } async fn kube_client() -> kube::Client { @@ -513,4 +498,41 @@ mod test { } false } + + use conductor::aws::cloudformation::AWSConfigState; + async fn check_cf_stack_deletion(acs: &AWSConfigState, stack_name: &str) -> bool { + let max_duration = Duration::from_secs(5 * 60); // 5 minutes + let check_interval = Duration::from_secs(30); // Check every 30 seconds + + let start_time = tokio::time::Instant::now(); + while tokio::time::Instant::now() - start_time < max_duration { + let exists = acs.does_stack_exist(stack_name).await; + println!("Checking if CF stack {} exists: {}", stack_name, exists); + + if !exists { + println!( + "CF stack {} does not exist, we assume it's deleted", + stack_name + ); + return true; + } else { + match acs.delete_cloudformation_stack(stack_name).await { + Ok(_) => { + println!("CF stack {} was deleted", stack_name); + } + Err(e) => { + panic!("Failed to delete CloudFormation stack: {:?}", e); + } + } + } + + tokio::time::sleep(check_interval).await; + } + + println!( + "CF stack {} was not deleted within the expected time.", + stack_name + ); + false + } } diff --git a/tembo-operator/Cargo.lock b/tembo-operator/Cargo.lock index 4347bb617..3bde68e7c 100644 --- a/tembo-operator/Cargo.lock +++ b/tembo-operator/Cargo.lock @@ -494,7 +494,7 @@ dependencies = [ [[package]] name = "controller" -version = "0.31.8" +version = "0.32.0" dependencies = [ "actix-web", "anyhow", diff --git a/tembo-operator/Cargo.toml b/tembo-operator/Cargo.toml index 85bd61ca5..a679d0e01 100644 --- a/tembo-operator/Cargo.toml +++ b/tembo-operator/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "controller" description = "Tembo Operator for Postgres" -version = "0.31.8" +version = "0.32.0" edition = "2021" default-run = "controller" license = "Apache-2.0" diff --git a/tembo-operator/src/apis/coredb_types.rs b/tembo-operator/src/apis/coredb_types.rs index 84f0c931d..8554c412e 100644 --- a/tembo-operator/src/apis/coredb_types.rs +++ b/tembo-operator/src/apis/coredb_types.rs @@ -389,7 +389,7 @@ pub struct CoreDBSpec { /// please visit our [tembo-images](https://github.com/tembo-io/tembo-images) repository. /// /// **Default**: quay.io/tembo/standard-cnpg:15.3.0-1-0c19c7e - #[serde(default = "defaults::default_image")] + #[serde(default = "defaults::default_image_uri")] pub image: String, /// **DEPRECATED** The postgres-exporter image you want to use for the postgres-exporter deployment. diff --git a/tembo-operator/src/cloudnativepg/cnpg.rs b/tembo-operator/src/cloudnativepg/cnpg.rs index d1801dbc7..2155a5d44 100644 --- a/tembo-operator/src/cloudnativepg/cnpg.rs +++ b/tembo-operator/src/cloudnativepg/cnpg.rs @@ -46,7 +46,7 @@ use crate::{ }, config::Config, configmap::custom_metrics_configmap_settings, - defaults::{default_image, default_llm_image}, + defaults::{default_dw_image_uri, default_image_uri, default_llm_image_uri}, errors::ValueError, is_postgres_ready, patch_cdb_status_merge, postgres_exporter::EXPORTER_CONFIGMAP_PREFIX, @@ -600,8 +600,9 @@ pub fn cnpg_cluster_from_cdb( // Check if the cdb.spec.image is set, if not then figure out which image to use. let image = if cdb.spec.image.is_empty() { match cdb.spec.stack.as_ref().map(|s| s.name.to_lowercase()) { - Some(ref name) if name == "machinelearning" => default_llm_image(), - _ => default_image(), + Some(ref name) if name == "machinelearning" => default_llm_image_uri(), + Some(ref name) if name == "datawarehouse" => default_dw_image_uri(), + _ => default_image_uri(), } } else { cdb.spec.image.clone() diff --git a/tembo-operator/src/defaults.rs b/tembo-operator/src/defaults.rs index 918233164..36a24daf1 100644 --- a/tembo-operator/src/defaults.rs +++ b/tembo-operator/src/defaults.rs @@ -10,6 +10,7 @@ use crate::{ }, cloudnativepg::poolers::{PoolerPgbouncerPoolMode, PoolerTemplateSpecContainersResources}, extensions::types::{Extension, TrunkInstall}, + stacks::{DATAWAREHOUSE, ML, STANDARD}, }; pub fn default_replicas() -> i32 { @@ -43,12 +44,41 @@ pub fn default_port() -> i32 { 5432 } +pub fn default_repository() -> String { + "quay.io/tembo".to_owned() +} + pub fn default_image() -> String { - "quay.io/tembo/standard-cnpg:15.3.0-1-0c19c7e".to_owned() + STANDARD + .image + .clone() + .expect("Standard or default image not found") } pub fn default_llm_image() -> String { - "quay.io/tembo/ml-cnpg:15.3.0-1-63e32a1".to_owned() + ML.image.clone().expect("ML image not found") +} + +pub fn default_dw_image() -> String { + DATAWAREHOUSE.image.clone().expect("DW image not found") +} + +pub fn default_image_uri() -> String { + let repo = default_repository(); + let image = default_image(); + format!("{}/{}", repo, image) +} + +pub fn default_llm_image_uri() -> String { + let repo = default_repository(); + let image = default_llm_image(); + format!("{}/{}", repo, image) +} + +pub fn default_dw_image_uri() -> String { + let repo = default_repository(); + let image = default_dw_image(); + format!("{}/{}", repo, image) } pub fn default_storage() -> Quantity { diff --git a/tembo-operator/src/extensions/toggle.rs b/tembo-operator/src/extensions/toggle.rs index ca5b86858..c04cb833e 100644 --- a/tembo-operator/src/extensions/toggle.rs +++ b/tembo-operator/src/extensions/toggle.rs @@ -405,7 +405,7 @@ async fn check_for_extensions_enabled_with_load( for extension in trunk_installed_extensions_not_in_all_actually_installed_extensions.clone() { let found = - check_for_so_files(cdb, ctx.clone(), &*pod_name, extension.name.clone()).await?; + check_for_so_files(cdb, ctx.clone(), &pod_name, extension.name.clone()).await?; // If found, add to extensions_with_load if found { // Get trunk project description for extension @@ -430,7 +430,7 @@ async fn check_for_extensions_enabled_with_load( found = true; for desired_location in desired_extension.locations { let location_status = ExtensionInstallLocationStatus { - enabled: Some(desired_location.enabled.clone()), + enabled: Some(desired_location.enabled), database: desired_location.database.clone(), schema: desired_location.schema.clone(), version: desired_location.version.clone(), diff --git a/tembo-operator/src/stacks/templates/api.yaml b/tembo-operator/src/stacks/templates/api.yaml index 6694969ec..c3f9723ad 100644 --- a/tembo-operator/src/stacks/templates/api.yaml +++ b/tembo-operator/src/stacks/templates/api.yaml @@ -1,6 +1,7 @@ name: API description: Tembo Stack with REST and graphQL interfaces. -image: "quay.io/tembo/standard-cnpg:15.3.0-1-795fc99" +repository: "quay.io/tembo" +image: "standard-cnpg:15.3.0-1-3d9a853" stack_version: 0.1.0 appServices: - image: postgrest/postgrest:v12.0.0 diff --git a/tembo-operator/src/stacks/templates/data_warehouse.yaml b/tembo-operator/src/stacks/templates/data_warehouse.yaml index 72c0a772e..e36478925 100644 --- a/tembo-operator/src/stacks/templates/data_warehouse.yaml +++ b/tembo-operator/src/stacks/templates/data_warehouse.yaml @@ -1,6 +1,7 @@ name: DataWarehouse description: A Postgres instance equipped with configuration and extensions for building a data warehouse on Postgres. -image: "quay.io/tembo/dw-cnpg:15.3.0-1-46c8b6f" +repository: "quay.io/tembo" +image: "dw-cnpg:15.3.0-1-3d9a853" stack_version: 0.1.0 compute_templates: - cpu: 2 diff --git a/tembo-operator/src/stacks/templates/gis.yaml b/tembo-operator/src/stacks/templates/gis.yaml index 5340f4879..5b792de58 100644 --- a/tembo-operator/src/stacks/templates/gis.yaml +++ b/tembo-operator/src/stacks/templates/gis.yaml @@ -1,6 +1,7 @@ name: Geospatial description: Postgres for geospatial workloads. -image: "quay.io/tembo/standard-cnpg:15.3.0-1-795fc99" +repository: "quay.io/tembo" +image: "standard-cnpg:15.3.0-1-3d9a853" stack_version: 0.1.0 compute_templates: - cpu: 0.25 diff --git a/tembo-operator/src/stacks/templates/machine_learning.yaml b/tembo-operator/src/stacks/templates/machine_learning.yaml index d9a288691..ee647f850 100644 --- a/tembo-operator/src/stacks/templates/machine_learning.yaml +++ b/tembo-operator/src/stacks/templates/machine_learning.yaml @@ -1,6 +1,7 @@ name: MachineLearning description: A Postgres instance equipped with machine learning extensions and optimized for machine learning workloads. -image: "quay.io/tembo/ml-cnpg:15.3.0-1-46c8b6f" +repository: "quay.io/tembo" +image: "ml-cnpg:15.3.0-1-3d9a853" stack_version: 0.3.0 compute_templates: - cpu: 2 diff --git a/tembo-operator/src/stacks/templates/message_queue.yaml b/tembo-operator/src/stacks/templates/message_queue.yaml index 823433044..0202df3eb 100644 --- a/tembo-operator/src/stacks/templates/message_queue.yaml +++ b/tembo-operator/src/stacks/templates/message_queue.yaml @@ -1,6 +1,7 @@ name: MessageQueue description: A Tembo Postgres Stack optimized for Message Queue workloads. -image: "quay.io/tembo/standard-cnpg:15.3.0-1-795fc99" +repository: "quay.io/tembo" +image: "standard-cnpg:15.3.0-1-3d9a853" stack_version: 0.3.0 appServices: - name: mq-api diff --git a/tembo-operator/src/stacks/templates/mongo_alternative.yaml b/tembo-operator/src/stacks/templates/mongo_alternative.yaml index 546414d68..4b6b4568d 100644 --- a/tembo-operator/src/stacks/templates/mongo_alternative.yaml +++ b/tembo-operator/src/stacks/templates/mongo_alternative.yaml @@ -1,6 +1,7 @@ name: MongoAlternative description: Document-facing workloads on Postgres. -image: "quay.io/tembo/standard-cnpg:15.3.0-1-795fc99" +repository: "quay.io/tembo" +image: "standard-cnpg:15.3.0-1-3d9a853" stack_version: 0.1.0 appServices: - name: fdb-api diff --git a/tembo-operator/src/stacks/templates/olap.yaml b/tembo-operator/src/stacks/templates/olap.yaml index 4634da915..82c29bc26 100644 --- a/tembo-operator/src/stacks/templates/olap.yaml +++ b/tembo-operator/src/stacks/templates/olap.yaml @@ -1,6 +1,7 @@ name: OLAP description: A Postgres instance equipped with configuration and extensions for OLAP workloads. -image: "quay.io/tembo/standard-cnpg:15.3.0-1-795fc99" +repository: "quay.io/tembo" +image: "standard-cnpg:15.3.0-1-3d9a853" stack_version: 0.1.0 compute_templates: - cpu: 0.25 diff --git a/tembo-operator/src/stacks/templates/oltp.yaml b/tembo-operator/src/stacks/templates/oltp.yaml index c4da02ec7..9eddae029 100644 --- a/tembo-operator/src/stacks/templates/oltp.yaml +++ b/tembo-operator/src/stacks/templates/oltp.yaml @@ -1,6 +1,7 @@ name: OLTP description: A Postgres instance optimized for OLTP workloads. -image: "quay.io/tembo/standard-cnpg:15.3.0-1-795fc99" +repository: "quay.io/tembo" +image: "standard-cnpg:15.3.0-1-3d9a853" stack_version: 0.1.0 compute_templates: - cpu: 0.25 diff --git a/tembo-operator/src/stacks/templates/standard.yaml b/tembo-operator/src/stacks/templates/standard.yaml index fe74530df..53df0451b 100644 --- a/tembo-operator/src/stacks/templates/standard.yaml +++ b/tembo-operator/src/stacks/templates/standard.yaml @@ -1,6 +1,7 @@ name: Standard description: A balanced Postgres instance optimized for OLTP workloads. -image: "quay.io/tembo/standard-cnpg:15.3.0-1-795fc99" +repository: "quay.io/tembo" +image: "standard-cnpg:15.3.0-1-3d9a853" stack_version: 0.1.0 compute_templates: - cpu: 0.25 diff --git a/tembo-operator/src/stacks/templates/vectordb.yaml b/tembo-operator/src/stacks/templates/vectordb.yaml index 245d9cea9..407d4dae9 100644 --- a/tembo-operator/src/stacks/templates/vectordb.yaml +++ b/tembo-operator/src/stacks/templates/vectordb.yaml @@ -1,6 +1,7 @@ name: VectorDB description: A Tembo Postgres Stack configured to support vector data types, storage, and operations. -image: "quay.io/tembo/standard-cnpg:15.3.0-1-795fc99" +repository: "quay.io/tembo" +image: "standard-cnpg:15.3.0-1-3d9a853" stack_version: 0.1.0 appServices: - image: quay.io/tembo/vector-serve:7dc6329 diff --git a/tembo-operator/src/stacks/types.rs b/tembo-operator/src/stacks/types.rs index cc5b077c1..14e76f44c 100644 --- a/tembo-operator/src/stacks/types.rs +++ b/tembo-operator/src/stacks/types.rs @@ -1,7 +1,7 @@ use crate::{ apis::postgres_parameters::PgConfig, app_service::types::AppService, - defaults::default_image, + defaults::{default_image, default_repository}, extensions::types::{Extension, TrunkInstall}, postgres_exporter::QueryConfig, stacks::config_engines::{ @@ -69,6 +69,8 @@ pub struct Stack { pub name: String, pub compute_templates: Option>, pub description: Option, + #[serde(default = "default_stack_repository")] + pub repository: Option, #[serde(default = "default_stack_image")] pub image: Option, pub stack_version: Option, @@ -98,6 +100,10 @@ impl Stack { } } +fn default_stack_repository() -> Option { + Some(default_repository()) +} + fn default_stack_image() -> Option { Some(default_image()) } diff --git a/tembo-operator/src/trunk.rs b/tembo-operator/src/trunk.rs index 4ac755b41..2e294c0f2 100644 --- a/tembo-operator/src/trunk.rs +++ b/tembo-operator/src/trunk.rs @@ -277,7 +277,7 @@ pub async fn get_trunk_project_metadata_for_version( let response_body = response.text().await?; let project_metadata: Vec = serde_json::from_str(&response_body)?; // There will only be one index here, so we can safely assume index 0 - let project_metadata = match project_metadata.get(0) { + let project_metadata = match project_metadata.first() { Some(project_metadata) => project_metadata, None => { error!( @@ -367,7 +367,7 @@ pub async fn is_control_file_absent( // where there are multiple extensions let control_file_absent = project_metadata .extensions - .get(0) + .first() .unwrap() .control_file .absent; @@ -411,18 +411,11 @@ pub async fn get_loadable_library_name( } }; // Find the loadable library in the extension metadata - let loadable_library_name = match extension_metadata.loadable_libraries { - Some(ref loadable_libraries) => { - let loadable_library = loadable_libraries - .iter() - .find(|l| l.requires_restart == true); - match loadable_library { - Some(loadable_library) => Some(loadable_library.library_name.clone()), - None => None, - } - } - None => None, - }; + let loadable_library_name = extension_metadata + .loadable_libraries + .as_ref() + .and_then(|loadable_libraries| loadable_libraries.iter().find(|l| l.requires_restart)) + .map(|loadable_library| loadable_library.library_name.clone()); Ok(loadable_library_name) } @@ -496,8 +489,8 @@ pub fn convert_to_semver(version: String) -> String { fn sort_semver(versions: Vec) -> Vec { let mut versions = versions; versions.sort_by(|a, b| { - let a = semver::Version::parse(&a).unwrap(); - let b = semver::Version::parse(&b).unwrap(); + let a = semver::Version::parse(a).unwrap(); + let b = semver::Version::parse(b).unwrap(); a.cmp(&b) }); versions @@ -550,17 +543,17 @@ mod tests { let extension_name = "auto_explain".to_string(); let result = extension_name_matches_trunk_project(extension_name).await; assert!(result.is_ok()); - assert_eq!(result.unwrap(), true); + assert!(result.unwrap()); let extension_name = "pgml".to_string(); let result = extension_name_matches_trunk_project(extension_name).await; assert!(result.is_ok()); - assert_eq!(result.unwrap(), false); + assert!(!result.unwrap()); let extension_name = "vector".to_string(); let result = extension_name_matches_trunk_project(extension_name).await; assert!(result.is_ok()); - assert_eq!(result.unwrap(), false); + assert!(!result.unwrap()); } #[tokio::test] @@ -592,7 +585,7 @@ mod tests { let version = "15.3.0".to_string(); let result = is_control_file_absent(trunk_project, version).await; assert!(result.is_ok()); - assert_eq!(result.unwrap(), true); + assert!(result.unwrap()); } #[tokio::test] @@ -618,11 +611,11 @@ mod tests { fn test_is_semver() { let version = "1.2.3".to_string(); let result = is_semver(version); - assert_eq!(result, true); + assert!(result); let version = "1.2".to_string(); let result = is_semver(version); - assert_eq!(result, false); + assert!(!result); } #[test] diff --git a/tembo-operator/tests/integration_tests.rs b/tembo-operator/tests/integration_tests.rs index 4a95308ea..75d9886ef 100644 --- a/tembo-operator/tests/integration_tests.rs +++ b/tembo-operator/tests/integration_tests.rs @@ -46,7 +46,6 @@ mod test { }; use rand::Rng; use reqwest::header::{HeaderMap, HeaderName, HeaderValue}; - use std::thread::sleep; use std::{ collections::{BTreeMap, BTreeSet}, ops::Not, @@ -613,19 +612,17 @@ mod test { attempt, max_retries, name, extension ); } + } else if has_extension { + println!( + "CoreDB {} has extension {} enabled in status", + name, extension + ); + return Ok(()); } else { - if has_extension { - println!( - "CoreDB {} has extension {} enabled in status", - name, extension - ); - return Ok(()); - } else { - println!( - "Attempt {}/{}: CoreDB {} has extension {} disabled in status", - attempt, max_retries, name, extension - ); - } + println!( + "Attempt {}/{}: CoreDB {} has extension {} disabled in status", + attempt, max_retries, name, extension + ); } } Err(e) => { @@ -2332,7 +2329,7 @@ mod test { }); let params = PatchParams::apply("tembo-integration-test"); let patch = Patch::Apply(&coredb_json); - let coredb_resource = coredbs.patch(name, ¶ms, &patch).await.unwrap(); + let _coredb_resource = coredbs.patch(name, ¶ms, &patch).await.unwrap(); // Wait for CNPG Pod to be created let pods: Api = Api::namespaced(client.clone(), &namespace); @@ -2346,7 +2343,7 @@ mod test { // Check status.extensions.locations is not empty let coredb_resource = coredbs.get(name).await.unwrap(); for extension in coredb_resource.status.unwrap().extensions.unwrap() { - assert!(extension.locations.len() > 0); + assert!(!extension.locations.is_empty()); } // Update CoreDB resource to enable extensions