From 4ff4faf45722ce039e0c18d56fae53512484919a Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Thu, 10 Feb 2022 16:31:11 +0100 Subject: [PATCH 01/12] hive and opa configmaps now mounted as env variables for discovery and properties replaced via script. --- deploy/crd/trinocluster.crd.yaml | 30 +- examples/simple-hive-cluster-derby.yaml | 25 -- examples/simple-opa-cluster.yaml | 14 - ...imple-trino-cluster-opa-authorization.yaml | 113 +++++++ examples/simple-trino-cluster.yaml | 68 ++-- examples/simple-trino-users-secret.yaml | 12 - rust/crd/src/authentication.rs | 26 +- rust/crd/src/lib.rs | 8 +- rust/operator-binary/src/controller.rs | 313 +++++++++--------- 9 files changed, 336 insertions(+), 273 deletions(-) delete mode 100644 examples/simple-hive-cluster-derby.yaml delete mode 100644 examples/simple-opa-cluster.yaml create mode 100644 examples/simple-trino-cluster-opa-authorization.yaml delete mode 100644 examples/simple-trino-users-secret.yaml diff --git a/deploy/crd/trinocluster.crd.yaml b/deploy/crd/trinocluster.crd.yaml index 2c1e91be..3f887d36 100644 --- a/deploy/crd/trinocluster.crd.yaml +++ b/deploy/crd/trinocluster.crd.yaml @@ -199,36 +199,14 @@ spec: required: - roleGroups type: object - hive: + hiveConfigMapName: nullable: true - properties: - chroot: - nullable: true - type: string - name: - type: string - namespace: - nullable: true - type: string - required: - - name - type: object + type: string nodeEnvironment: type: string - opa: + opaConfigMapName: nullable: true - properties: - chroot: - nullable: true - type: string - name: - type: string - namespace: - nullable: true - type: string - required: - - name - type: object + type: string s3: description: Contains all the required connection information for S3. nullable: true diff --git a/examples/simple-hive-cluster-derby.yaml b/examples/simple-hive-cluster-derby.yaml deleted file mode 100644 index 88413d10..00000000 --- a/examples/simple-hive-cluster-derby.yaml +++ /dev/null @@ -1,25 +0,0 @@ -apiVersion: hive.stackable.tech/v1alpha1 -kind: HiveCluster -metadata: - name: simple-hive-derby -spec: - version: 2.3.9 - metastore: - roleGroups: - default: - selector: - matchLabels: - kubernetes.io/os: linux - replicas: 1 - config: - database: - connString: jdbc:derby:;databaseName=/stackable/metastore_db;create=true - user: APP - password: mine - dbType: derby - s3Connection: - endPoint: changeme - accessKey: changeme - secretKey: changeme - sslEnabled: false - pathStyleAccess: true diff --git a/examples/simple-opa-cluster.yaml b/examples/simple-opa-cluster.yaml deleted file mode 100644 index c9609cfd..00000000 --- a/examples/simple-opa-cluster.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: opa.stackable.tech/v1alpha1 -kind: OpenPolicyAgent -metadata: - name: simple-opa -spec: - version: "0.27.1" - servers: - roleGroups: - default: - selector: - matchLabels: - kubernetes.io/os: linux - config: - regoRuleReference: "http://regorule-operator:3030/opa/v1" diff --git a/examples/simple-trino-cluster-opa-authorization.yaml b/examples/simple-trino-cluster-opa-authorization.yaml new file mode 100644 index 00000000..c82634a3 --- /dev/null +++ b/examples/simple-trino-cluster-opa-authorization.yaml @@ -0,0 +1,113 @@ +--- +apiVersion: hive.stackable.tech/v1alpha1 +kind: HiveCluster +metadata: + name: simple-hive-derby +spec: + version: 2.3.9 + metastore: + roleGroups: + default: + selector: + matchLabels: + kubernetes.io/os: linux + replicas: 1 + config: + database: + connString: jdbc:derby:;databaseName=/stackable/metastore_db;create=true + user: APP + password: mine + dbType: derby + s3Connection: + endPoint: changeme + accessKey: changeme + secretKey: changeme + sslEnabled: false + pathStyleAccess: true +--- +apiVersion: opa.stackable.tech/v1alpha1 +kind: OpenPolicyAgent +metadata: + name: simple-opa +spec: + version: "0.27.1" + servers: + roleGroups: + default: + selector: + matchLabels: + kubernetes.io/os: linux + config: + regoRuleReference: "http://regorule-operator:3030/opa/v1" +--- +apiVersion: v1 +kind: Secret +metadata: + name: simple-trino-users-secret +type: kubernetes.io/opaque +stringData: + # admin:admin + admin: $2y$10$89xReovvDLacVzRGpjOyAOONnayOgDAyIS2nW9bs5DJT98q17Dy5i + # alice:alice + alice: $2y$10$HcCa4k9v2DRrD/g7e5vEz.Bk.1xg00YTEHOZjPX7oK3KqMSt2xT8W + # bob:bob + bob: $2y$10$xVRXtYZnYuQu66SmruijPO8WHFM/UK5QPHTr.Nzf4JMcZSqt3W.2. +--- +apiVersion: trino.stackable.tech/v1alpha1 +kind: TrinoCluster +metadata: + name: simple-trino +spec: + version: "0.0.362" + nodeEnvironment: production + hiveConfigMapName: simple-hive-derby + opaConfigMapName: simple-opa + authentication: + method: + multiUser: + userCredentialsSecret: + namespace: default + name: simple-trino-users-secret + authorization: + package: trino + permissions: + admin: + schemas: + read: true + write: true + tables: + iris_parquet: + read: true + write: true + iris_csv: + read: true + write: true + bob: + schemas: + read: false + write: false + tables: + iris_parquet: + read: true + s3: + endPoint: changeme + accessKey: changeme + secretKey: changeme + sslEnabled: false + pathStyleAccess: true + coordinators: + roleGroups: + default: + selector: + matchLabels: + kubernetes.io/os: linux + replicas: 1 + config: {} + workers: + roleGroups: + default: + selector: + matchLabels: + kubernetes.io/os: linux + replicas: 1 + config: {} diff --git a/examples/simple-trino-cluster.yaml b/examples/simple-trino-cluster.yaml index ef7728fb..a1af1c87 100644 --- a/examples/simple-trino-cluster.yaml +++ b/examples/simple-trino-cluster.yaml @@ -1,3 +1,43 @@ +--- +apiVersion: hive.stackable.tech/v1alpha1 +kind: HiveCluster +metadata: + name: simple-hive-derby +spec: + version: 2.3.9 + metastore: + roleGroups: + default: + selector: + matchLabels: + kubernetes.io/os: linux + replicas: 1 + config: + database: + connString: jdbc:derby:;databaseName=/stackable/metastore_db;create=true + user: APP + password: mine + dbType: derby + s3Connection: + endPoint: changeme + accessKey: changeme + secretKey: changeme + sslEnabled: false + pathStyleAccess: true +--- +apiVersion: v1 +kind: Secret +metadata: + name: simple-trino-users-secret +type: kubernetes.io/opaque +stringData: + # admin:admin + admin: $2y$10$89xReovvDLacVzRGpjOyAOONnayOgDAyIS2nW9bs5DJT98q17Dy5i + # alice:alice + alice: $2y$10$HcCa4k9v2DRrD/g7e5vEz.Bk.1xg00YTEHOZjPX7oK3KqMSt2xT8W + # bob:bob + bob: $2y$10$xVRXtYZnYuQu66SmruijPO8WHFM/UK5QPHTr.Nzf4JMcZSqt3W.2. +--- apiVersion: trino.stackable.tech/v1alpha1 kind: TrinoCluster metadata: @@ -5,39 +45,13 @@ metadata: spec: version: "0.0.362" nodeEnvironment: production - hive: - namespace: default - name: simple-hive-derby - opa: - namespace: default - name: simple-opa + hiveConfigMapName: simple-hive-derby authentication: method: multiUser: userCredentialsSecret: namespace: default name: simple-trino-users-secret - authorization: - package: trino - permissions: - admin: - schemas: - read: true - write: true - tables: - iris_parquet: - read: true - write: true - iris_csv: - read: true - write: true - bob: - schemas: - read: false - write: false - tables: - iris_parquet: - read: true s3: endPoint: changeme accessKey: changeme diff --git a/examples/simple-trino-users-secret.yaml b/examples/simple-trino-users-secret.yaml deleted file mode 100644 index 1552f243..00000000 --- a/examples/simple-trino-users-secret.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: simple-trino-users-secret -type: kubernetes.io/opaque -stringData: - # admin:admin - admin: $2y$10$89xReovvDLacVzRGpjOyAOONnayOgDAyIS2nW9bs5DJT98q17Dy5i - # alice:alice - alice: $2y$10$HcCa4k9v2DRrD/g7e5vEz.Bk.1xg00YTEHOZjPX7oK3KqMSt2xT8W - # bob:bob - bob: $2y$10$xVRXtYZnYuQu66SmruijPO8WHFM/UK5QPHTr.Nzf4JMcZSqt3W.2. diff --git a/rust/crd/src/authentication.rs b/rust/crd/src/authentication.rs index 124f0b10..216cabcb 100644 --- a/rust/crd/src/authentication.rs +++ b/rust/crd/src/authentication.rs @@ -50,13 +50,6 @@ pub enum TrinoAuthenticationMethod { }, } -#[derive(Clone, Debug, PartialEq)] -pub enum TrinoAuthenticationConfig { - MultiUser { - user_credentials: BTreeMap, - }, -} - impl TrinoAuthenticationMethod { pub async fn materialize( &self, @@ -108,3 +101,22 @@ impl TrinoAuthenticationMethod { } } } + +#[derive(Clone, Debug, PartialEq)] +pub enum TrinoAuthenticationConfig { + MultiUser { + user_credentials: BTreeMap, + }, +} + +impl TrinoAuthenticationConfig { + pub fn to_trino_user_data(&self) -> String { + match self { + TrinoAuthenticationConfig::MultiUser { user_credentials } => user_credentials + .iter() + .map(|(user, password)| format!("{}:{}", user, password)) + .collect::>() + .join("\n"), + } + } +} diff --git a/rust/crd/src/lib.rs b/rust/crd/src/lib.rs index d6aad459..b9d27d50 100644 --- a/rust/crd/src/lib.rs +++ b/rust/crd/src/lib.rs @@ -39,6 +39,7 @@ pub const LOG_PROPERTIES: &str = "log.properties"; pub const PASSWORD_AUTHENTICATOR_PROPERTIES: &str = "password-authenticator.properties"; pub const PASSWORD_DB: &str = "password.db"; pub const HIVE_PROPERTIES: &str = "hive.properties"; +pub const ACCESS_CONTROL_PROPERTIES: &str = "access-control.properties"; // node.properties pub const NODE_ENVIRONMENT: &str = "node.environment"; pub const NODE_ID: &str = "node.id"; @@ -74,6 +75,7 @@ pub const IO_TRINO: &str = "io.trino"; pub const METRICS_PORT_PROPERTY: &str = "metricsPort"; // directories pub const CONFIG_DIR_NAME: &str = "/stackable/conf"; +pub const RW_CONFIG_DIR_NAME: &str = "/stackable/rwconf"; pub const DATA_DIR_NAME: &str = "/stackable/data"; pub const KEYSTORE_DIR_NAME: &str = "/stackable/keystore"; pub const USER_PASSWORD_DATA: &str = "/stackable/users"; @@ -81,7 +83,7 @@ pub const USER_PASSWORD_DATA: &str = "/stackable/users"; #[derive(Snafu, Debug)] pub enum Error { #[snafu(display("object has no namespace associated"))] - NoNamespaceError, + NoNamespace, #[snafu(display("Unknown Trino role found {role}. Should be one of {roles:?}"))] UnknownTrinoRole { role: String, roles: Vec }, } @@ -110,9 +112,9 @@ pub struct TrinoClusterSpec { pub version: Option, pub node_environment: String, #[serde(default, skip_serializing_if = "Option::is_none")] - pub hive: Option, + pub hive_config_map_name: Option, #[serde(default, skip_serializing_if = "Option::is_none")] - pub opa: Option, + pub opa_config_map_name: Option, /// A reference to a secret containing username/password for defined users #[serde(default, skip_serializing_if = "Option::is_none")] pub authentication: Option, diff --git a/rust/operator-binary/src/controller.rs b/rust/operator-binary/src/controller.rs index 595c1adf..a812a583 100644 --- a/rust/operator-binary/src/controller.rs +++ b/rust/operator-binary/src/controller.rs @@ -2,10 +2,10 @@ use snafu::{OptionExt, ResultExt, Snafu}; use stackable_operator::client::Client; use stackable_operator::k8s_openapi::api::core::v1::{ - CSIVolumeSource, ContainerPort, Probe, SecurityContext, TCPSocketAction, + CSIVolumeSource, ConfigMapKeySelector, ContainerPort, EmptyDirVolumeSource, EnvVarSource, + Probe, SecurityContext, TCPSocketAction, }; use stackable_operator::k8s_openapi::apimachinery::pkg::util::intstr::IntOrString; -use stackable_operator::kube::runtime::reflector::ObjectRef; use stackable_operator::kube::ResourceExt; use stackable_operator::product_config_utils::ValidatedRoleConfigByPropertyKind; use stackable_operator::role_utils::RoleGroupRef; @@ -35,11 +35,11 @@ use stackable_trino_crd::authentication::TrinoAuthenticationConfig; use stackable_trino_crd::authorization::create_rego_rules; use stackable_trino_crd::discovery::{TrinoDiscovery, TrinoDiscoveryProtocol, TrinoPodRef}; use stackable_trino_crd::{ - authentication, authorization, ClusterRef, TrinoCluster, TrinoClusterSpec, CONFIG_DIR_NAME, - CONFIG_PROPERTIES, DATA_DIR_NAME, DISCOVERY_URI, FIELD_MANAGER_SCOPE, HIVE_PROPERTIES, - HTTPS_PORT, HTTPS_PORT_NAME, HTTP_PORT_NAME, JVM_CONFIG, KEYSTORE_DIR_NAME, LOG_PROPERTIES, - METRICS_PORT, METRICS_PORT_NAME, NODE_PROPERTIES, PASSWORD_AUTHENTICATOR_PROPERTIES, - PASSWORD_DB, USER_PASSWORD_DATA, + authentication, authorization, TrinoCluster, TrinoClusterSpec, ACCESS_CONTROL_PROPERTIES, + CONFIG_DIR_NAME, CONFIG_PROPERTIES, DATA_DIR_NAME, DISCOVERY_URI, FIELD_MANAGER_SCOPE, + HIVE_PROPERTIES, HTTPS_PORT, HTTPS_PORT_NAME, HTTP_PORT_NAME, JVM_CONFIG, KEYSTORE_DIR_NAME, + LOG_PROPERTIES, METRICS_PORT, METRICS_PORT_NAME, NODE_PROPERTIES, + PASSWORD_AUTHENTICATOR_PROPERTIES, PASSWORD_DB, RW_CONFIG_DIR_NAME, USER_PASSWORD_DATA, }; use stackable_trino_crd::{TrinoRole, APP_NAME, HTTP_PORT}; use std::{ @@ -48,6 +48,7 @@ use std::{ sync::Arc, time::Duration, }; +use tracing::warn; pub struct Ctx { pub client: stackable_operator::client::Client, @@ -102,27 +103,13 @@ pub enum Error { source: stackable_operator::product_config_utils::ConfigError, }, #[snafu(display("failed to format runtime properties"))] - PropertiesWriteError { + FailedToWriteJavaProperties { source: stackable_operator::product_config::writer::PropertiesWriterError, }, - #[snafu(display("Failed to load Product Config"))] + #[snafu(display("failed to load Product Config"))] ProductConfigLoadFailed, - #[snafu(display("failed to create rego rules for authorization"))] - RegoRuleAuthorizationError { source: authorization::Error }, - #[snafu(display("failed to get config map {}", config_map))] - MissingConfigMap { - source: stackable_operator::error::Error, - config_map: ObjectRef, - }, - #[snafu(display( - "failed to get [{}] connection string from config map {}", - product, - config_map - ))] - MissingConnectString { - product: String, - config_map: ObjectRef, - }, + #[snafu(display("failed to write rego rules for authorization"))] + WriteRegoRuleAuthorizationFailed { source: authorization::Error }, #[snafu(display("failed to processing authentication config element from k8s"))] FailedProcessingAuthentication { source: authentication::Error }, #[snafu(display("internal operator failure"))] @@ -145,10 +132,12 @@ pub async fn reconcile_trino( let validated_config = validated_product_config(&trino, version, &ctx.get_ref().product_config)?; + let authentication_config = user_authentication(&trino, client).await?; + // rego rules create_rego_rules(client, &trino) .await - .context(RegoRuleAuthorizationSnafu)?; + .context(WriteRegoRuleAuthorizationFailedSnafu)?; let coordinator_role_service = build_coordinator_role_service(&trino)?; client @@ -160,41 +149,21 @@ pub async fn reconcile_trino( .await .context(ApplyRoleServiceSnafu)?; - let opa_connect = opa_connect(&trino, &ctx.get_ref().client).await?; - let hive_connect = hive_connect(&trino, &ctx.get_ref().client).await?; - - let authentication_config = match &trino.spec.authentication { - Some(authentication) => Some( - authentication - .method - .materialize( - client, - trino - .namespace() - .as_deref() - .context(ObjectHasNoNamespaceSnafu)?, - ) - .await - .context(FailedProcessingAuthenticationSnafu)?, - ), - _ => None, - }; - for (role, role_config) in validated_config { let trino_role = TrinoRole::from_str(&role).context(InternalOperatorFailureSnafu)?; for (role_group, config) in role_config { let rolegroup = trino_role.rolegroup_ref(&trino, role_group); let rg_service = build_rolegroup_service(&trino, &rolegroup)?; let rg_configmap = - build_rolegroup_config_map(&trino, &trino_role, &rolegroup, &config, &opa_connect)?; + build_rolegroup_config_map(&trino, &trino_role, &rolegroup, &config)?; let rg_catalog_configmap = - build_rolegroup_catalog_config_map(&trino, &rolegroup, &config, &hive_connect)?; + build_rolegroup_catalog_config_map(&trino, &rolegroup, &config)?; let rg_stateful_set = build_rolegroup_statefulset( &trino, &trino_role, &rolegroup, &config, - &authentication_config, + authentication_config.to_owned(), )?; client @@ -267,7 +236,6 @@ fn build_rolegroup_config_map( _role: &TrinoRole, rolegroup_ref: &RoleGroupRef, config: &HashMap>, - opa_connect: &Option, ) -> Result { let mut cm_conf_data = BTreeMap::new(); @@ -313,7 +281,7 @@ fn build_rolegroup_config_map( let config_properties = product_config::writer::to_java_properties_string(transformed_config.iter()) - .context(PropertiesWriteSnafu)?; + .context(FailedToWriteJavaPropertiesSnafu)?; cm_conf_data.insert(file_name.to_string(), config_properties); } @@ -321,21 +289,21 @@ fn build_rolegroup_config_map( PropertyNameKind::File(file_name) if file_name == NODE_PROPERTIES => { let node_properties = product_config::writer::to_java_properties_string(transformed_config.iter()) - .context(PropertiesWriteSnafu)?; + .context(FailedToWriteJavaPropertiesSnafu)?; cm_conf_data.insert(file_name.to_string(), node_properties); } PropertyNameKind::File(file_name) if file_name == LOG_PROPERTIES => { let log_properties = product_config::writer::to_java_properties_string(transformed_config.iter()) - .context(PropertiesWriteSnafu)?; + .context(FailedToWriteJavaPropertiesSnafu)?; cm_conf_data.insert(file_name.to_string(), log_properties); } PropertyNameKind::File(file_name) if file_name == PASSWORD_AUTHENTICATOR_PROPERTIES => { let pw_properties = product_config::writer::to_java_properties_string(transformed_config.iter()) - .context(PropertiesWriteSnafu)?; + .context(FailedToWriteJavaPropertiesSnafu)?; cm_conf_data.insert(file_name.to_string(), pw_properties); } PropertyNameKind::File(file_name) if file_name == PASSWORD_DB => { @@ -349,31 +317,19 @@ fn build_rolegroup_config_map( } } - if let Some(opa) = opa_connect { - let package = match trino.spec.authorization.as_ref() { - Some(auth) => auth.package.clone(), - None => { - println!("No package specified in 'authorization'. Defaulting to 'trino'."); - "trino".to_string() - } - }; - + if trino.spec.opa_config_map_name.is_some() { let mut opa_config = BTreeMap::new(); - + // the "opa.policy.uri" property will be added via command script later from the env variable "OPA" opa_config.insert( "access-control.name".to_string(), Some("tech.stackable.trino.opa.OpaAuthorizer".to_string()), ); - opa_config.insert( - "opa.policy.uri".to_string(), - Some(format!("{}v1/data/{}/", opa, package)), - ); let config_properties = product_config::writer::to_java_properties_string(opa_config.iter()) - .context(PropertiesWriteSnafu)?; + .context(FailedToWriteJavaPropertiesSnafu)?; - cm_conf_data.insert("access-control.properties".to_string(), config_properties); + cm_conf_data.insert(ACCESS_CONTROL_PROPERTIES.to_string(), config_properties); } cm_conf_data.insert(JVM_CONFIG.to_string(), jvm_config.to_string()); @@ -407,7 +363,6 @@ fn build_rolegroup_catalog_config_map( trino: &TrinoCluster, rolegroup_ref: &RoleGroupRef, config: &HashMap>, - hive_connect: &Option, ) -> Result { let mut cm_hive_data = BTreeMap::new(); @@ -419,16 +374,16 @@ fn build_rolegroup_catalog_config_map( match property_name_kind { PropertyNameKind::File(file_name) if file_name == HIVE_PROPERTIES => { - if let Some(hive_connect) = &hive_connect { + if trino.spec.hive_config_map_name.is_some() { + // hive.metastore.uri will be added later via command script from the + // "HIVE" env variable transformed_config .insert("connector.name".to_string(), Some("hive".to_string())); - transformed_config - .insert("hive.metastore.uri".to_string(), Some(hive_connect.clone())); let config_properties = product_config::writer::to_java_properties_string( transformed_config.iter(), ) - .context(PropertiesWriteSnafu)?; + .context(FailedToWriteJavaPropertiesSnafu)?; cm_hive_data.insert(file_name.to_string(), config_properties); } @@ -469,7 +424,7 @@ fn build_rolegroup_statefulset( role: &TrinoRole, rolegroup_ref: &RoleGroupRef, config: &HashMap>, - authentication_config: &Option, + authentication_config: Option, ) -> Result { let rolegroup = role .get_spec(trino) @@ -483,7 +438,8 @@ fn build_rolegroup_statefulset( "docker.stackable.tech/stackable/trino:{}-stackable0", trino_version ); - let env = config + + let mut env = config .get(&PropertyNameKind::Env) .iter() .flat_map(|env_vars| env_vars.iter()) @@ -494,13 +450,12 @@ fn build_rolegroup_statefulset( }) .collect::>(); - let user_data = match authentication_config { - Some(TrinoAuthenticationConfig::MultiUser { user_credentials }) => user_credentials - .iter() - .map(|(user, password)| format!("{}:{}", user, password)) - .collect::>() - .join("\n"), - None => String::new(), + if let Some(opa) = discovery_config_map(&trino.spec.opa_config_map_name, "OPA") { + env.push(opa); + }; + + if let Some(hive) = discovery_config_map(&trino.spec.hive_config_map_name, "HIVE") { + env.push(hive); }; let mut container_prepare = ContainerBuilder::new("prepare") @@ -523,7 +478,7 @@ fn build_rolegroup_statefulset( "echo chmodding keystore directory", "chmod -R a=,u=rwX /stackable/keystore", ].join(" && ")]) - .add_volume_mount("keystore", "/stackable/keystore") + .add_volume_mount("keystore", KEYSTORE_DIR_NAME) .build(); container_prepare @@ -534,22 +489,11 @@ fn build_rolegroup_statefulset( let container_trino = ContainerBuilder::new(APP_NAME) .image(image) .command(vec!["/bin/bash".to_string(), "-c".to_string()]) - .args(vec![[ - format!( - "echo Writing user data to {}/{}", - USER_PASSWORD_DATA, PASSWORD_DB - ), - format!("mkdir {}", USER_PASSWORD_DATA), - format!( - "echo '{}' > {}/{} ", - user_data, USER_PASSWORD_DATA, PASSWORD_DB - ), - format!("bin/launcher run --etc-dir={}", CONFIG_DIR_NAME), - ] - .join(" && ")]) + .args(container_trino_args(trino, authentication_config)) .add_env_vars(env) .add_volume_mount("data", DATA_DIR_NAME) .add_volume_mount("conf", CONFIG_DIR_NAME) + .add_volume_mount("rwconf", RW_CONFIG_DIR_NAME) .add_volume_mount("keystore", KEYSTORE_DIR_NAME) .add_volume_mount("catalog", format!("{}/catalog", CONFIG_DIR_NAME)) .add_container_ports(container_ports()) @@ -624,6 +568,14 @@ fn build_rolegroup_statefulset( }), ..Volume::default() }) + .add_volume(Volume { + empty_dir: Some(EmptyDirVolumeSource { + medium: None, + size_limit: None, + }), + name: "rwconf".to_string(), + ..Volume::default() + }) .add_volume(Volume { name: "catalog".to_string(), config_map: Some(ConfigMapVolumeSource { @@ -729,55 +681,118 @@ pub fn error_policy(_error: &Error, _ctx: Context) -> ReconcilerAction { } } -async fn opa_connect(trino: &TrinoCluster, client: &Client) -> Result> { - let mut opa_connect_string = None; - - let spec: &TrinoClusterSpec = &trino.spec; - - if let Some(opa_reference) = &spec.opa { - let product = "OPA"; - - let (name, namespace) = name_and_namespace(trino, opa_reference)?; - - opa_connect_string = Some(cluster_ref_cm_data(client, &name, &namespace, product).await?); - } - - Ok(opa_connect_string) +async fn user_authentication( + trino: &TrinoCluster, + client: &Client, +) -> Result> { + Ok(match &trino.spec.authentication { + Some(authentication) => Some( + authentication + .method + .materialize( + client, + trino + .namespace() + .as_deref() + .context(ObjectHasNoNamespaceSnafu)?, + ) + .await + .context(FailedProcessingAuthenticationSnafu)?, + ), + _ => None, + }) } -async fn hive_connect(trino: &TrinoCluster, client: &Client) -> Result> { - let mut hive_connect_string = None; - - if let Some(hive_reference) = &trino.spec.hive { - let product = "HIVE"; +fn container_trino_args( + trino: &TrinoCluster, + user_authentication: Option, +) -> Vec { + let mut args = vec![ + // copy config files to a writeable empty folder + format!( + "echo Copying {conf} to {rw_conf}", + conf = CONFIG_DIR_NAME, + rw_conf = RW_CONFIG_DIR_NAME + ), + format!( + "cp -RL {conf}/* {rw_conf}", + conf = CONFIG_DIR_NAME, + rw_conf = RW_CONFIG_DIR_NAME + ), + ]; - let (name, namespace) = name_and_namespace(trino, hive_reference)?; + if let Some(auth) = user_authentication { + let user_data = auth.to_trino_user_data(); + args.extend(vec![ + format!( + "echo Writing user data to {path}/{db}", + path = USER_PASSWORD_DATA, + db = PASSWORD_DB + ), + format!("mkdir {}", USER_PASSWORD_DATA), + format!( + "echo '{data}' > {path}/{db} ", + data = user_data, + path = USER_PASSWORD_DATA, + db = PASSWORD_DB + ), + ]) + } + // hive required? + if trino.spec.hive_config_map_name.is_some() { + args.extend(vec![ + format!( "echo Writing HIVE connect string \"hive.metastore.uri=${{HIVE}}\" to {rw_conf}/catalog/{hive_properties}", + rw_conf = RW_CONFIG_DIR_NAME, hive_properties = HIVE_PROPERTIES + ), + format!( "echo \"hive.metastore.uri=${{HIVE}}\" >> {rw_conf}/catalog/{hive_properties}", + rw_conf = RW_CONFIG_DIR_NAME, hive_properties = HIVE_PROPERTIES + )]) + } + // opa required? + if trino.spec.opa_config_map_name.is_some() { + let opa_package_name = match trino.spec.authorization.as_ref() { + Some(auth) => auth.package.clone(), + None => { + warn!("No package specified in 'spec.authorization'. Defaulting to 'trino'."); + "trino".to_string() + } + }; - hive_connect_string = cluster_ref_cm_data(client, &name, &namespace, product) - .await? - // TODO: hive now offers all pods fqdn(s) instead of the service - // this should be removed - .split('\n') - .collect::>() - .into_iter() - .next() - .map(|s| s.to_string()); + args.extend(vec![ + format!( "echo Writing OPA connect string \"opa.policy.uri=${{OPA}}v1/data/{package_name}\" to {rw_conf}/{access_control}", + package_name = opa_package_name, rw_conf = RW_CONFIG_DIR_NAME, access_control = ACCESS_CONTROL_PROPERTIES + ), + format!( "echo \"opa.policy.uri=${{OPA}}v1/data/{package_name}/\" >> {rw_conf}/{access_control}", + package_name = opa_package_name, rw_conf = RW_CONFIG_DIR_NAME, access_control = ACCESS_CONTROL_PROPERTIES + )]) } - Ok(hive_connect_string) -} + // start command + args.push(format!( + "bin/launcher run --etc-dir={conf} --data-dir={data}", + conf = RW_CONFIG_DIR_NAME, + data = DATA_DIR_NAME + )); -/// Return the name and adapted namespace of the `cluster_ref`. -/// If `cluster_ref` has no namespace defined we default to the `trino` namespace. -/// If `trino` has no namespace defined we throw an error. -fn name_and_namespace(trino: &TrinoCluster, cluster_ref: &ClusterRef) -> Result<(String, String)> { - let name = cluster_ref.name.clone(); - let namespace = match &cluster_ref.namespace { - Some(ns) => ns.clone(), - None => trino.namespace().context(ObjectHasNoNamespaceSnafu)?, - }; + vec![args.join(" && ")] +} - Ok((name, namespace)) +fn discovery_config_map(config_map_name: &Option, env_var: &str) -> Option { + match config_map_name { + Some(cm_name) => Some(EnvVar { + name: env_var.to_string(), + value_from: Some(EnvVarSource { + config_map_key_ref: Some(ConfigMapKeySelector { + name: Some(cm_name.to_string()), + key: env_var.to_string(), + ..ConfigMapKeySelector::default() + }), + ..EnvVarSource::default() + }), + ..EnvVar::default() + }), + None => None, + } } /// Defines all required roles and their required configuration. @@ -845,26 +860,6 @@ fn validated_product_config( .context(InvalidProductConfigSnafu) } -async fn cluster_ref_cm_data( - client: &Client, - name: &str, - namespace: &str, - product_name: &str, -) -> Result { - Ok(client - .get::(name, Some(namespace)) - .await - .with_context(|_| MissingConfigMapSnafu { - config_map: ObjectRef::new(name).within(namespace), - })? - .data - .and_then(|mut data| data.remove(product_name)) - .with_context(|| MissingConnectStringSnafu { - product: product_name.to_string(), - config_map: ObjectRef::new(name).within(namespace), - })?) -} - fn service_ports() -> Vec { vec![ ServicePort { From c3d4f196eb71a9dba835754130e63b2f91379fb2 Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Thu, 10 Feb 2022 16:55:03 +0100 Subject: [PATCH 02/12] trino now can be used insecurely via http or with authentication via https --- deploy/config-spec/properties.yaml | 2 +- ...ter-authentication-opa-authorization.yaml} | 0 examples/simple-trino-cluster.yaml | 19 --- rust/crd/src/lib.rs | 19 +-- rust/operator-binary/src/controller.rs | 108 +++++++++++------- 5 files changed, 80 insertions(+), 68 deletions(-) rename examples/{simple-trino-cluster-opa-authorization.yaml => simple-trino-cluster-authentication-opa-authorization.yaml} (100%) diff --git a/deploy/config-spec/properties.yaml b/deploy/config-spec/properties.yaml index 43e5e607..8450b4ac 100644 --- a/deploy/config-spec/properties.yaml +++ b/deploy/config-spec/properties.yaml @@ -115,7 +115,7 @@ properties: value: "8443" roles: - name: "coordinator" - required: true + required: false asOfVersion: "0.0.0" - property: &queryMaxMemory diff --git a/examples/simple-trino-cluster-opa-authorization.yaml b/examples/simple-trino-cluster-authentication-opa-authorization.yaml similarity index 100% rename from examples/simple-trino-cluster-opa-authorization.yaml rename to examples/simple-trino-cluster-authentication-opa-authorization.yaml diff --git a/examples/simple-trino-cluster.yaml b/examples/simple-trino-cluster.yaml index a1af1c87..b3fb0e48 100644 --- a/examples/simple-trino-cluster.yaml +++ b/examples/simple-trino-cluster.yaml @@ -25,19 +25,6 @@ spec: sslEnabled: false pathStyleAccess: true --- -apiVersion: v1 -kind: Secret -metadata: - name: simple-trino-users-secret -type: kubernetes.io/opaque -stringData: - # admin:admin - admin: $2y$10$89xReovvDLacVzRGpjOyAOONnayOgDAyIS2nW9bs5DJT98q17Dy5i - # alice:alice - alice: $2y$10$HcCa4k9v2DRrD/g7e5vEz.Bk.1xg00YTEHOZjPX7oK3KqMSt2xT8W - # bob:bob - bob: $2y$10$xVRXtYZnYuQu66SmruijPO8WHFM/UK5QPHTr.Nzf4JMcZSqt3W.2. ---- apiVersion: trino.stackable.tech/v1alpha1 kind: TrinoCluster metadata: @@ -46,12 +33,6 @@ spec: version: "0.0.362" nodeEnvironment: production hiveConfigMapName: simple-hive-derby - authentication: - method: - multiUser: - userCredentialsSecret: - namespace: default - name: simple-trino-users-secret s3: endPoint: changeme accessKey: changeme diff --git a/rust/crd/src/lib.rs b/rust/crd/src/lib.rs index b9d27d50..f2987ae8 100644 --- a/rust/crd/src/lib.rs +++ b/rust/crd/src/lib.rs @@ -298,6 +298,10 @@ impl Configuration for TrinoConfig { HTTP_SERVER_HTTPS_ENABLED.to_string(), Some(true.to_string()), ); + result.insert( + HTTP_SERVER_HTTPS_PORT.to_string(), + Some(HTTPS_PORT.to_string()), + ); result.insert( HTTP_SERVER_KEYSTORE_PATH.to_string(), Some(format!("{}/{}", KEYSTORE_DIR_NAME, "keystore.p12")), @@ -307,15 +311,14 @@ impl Configuration for TrinoConfig { "http-server.https.keystore.key".to_string(), Some("secret".to_string()), ); - } - if resource.spec.authentication.is_some() - && role_name == TrinoRole::Coordinator.to_string() - { - result.insert( - HTTP_SERVER_AUTHENTICATION_TYPE.to_string(), - Some(HTTP_SERVER_AUTHENTICATION_TYPE_PASSWORD.to_string()), - ); + // password ui login + if role_name == TrinoRole::Coordinator.to_string() { + result.insert( + HTTP_SERVER_AUTHENTICATION_TYPE.to_string(), + Some(HTTP_SERVER_AUTHENTICATION_TYPE_PASSWORD.to_string()), + ); + } } } PASSWORD_AUTHENTICATOR_PROPERTIES => { diff --git a/rust/operator-binary/src/controller.rs b/rust/operator-binary/src/controller.rs index a812a583..47d4716a 100644 --- a/rust/operator-binary/src/controller.rs +++ b/rust/operator-binary/src/controller.rs @@ -221,7 +221,7 @@ pub fn build_coordinator_role_service(trino: &TrinoCluster) -> Result { .with_recommended_labels(trino, APP_NAME, trino_version(trino)?, &role_name, "global") .build(), spec: Some(ServiceSpec { - ports: Some(service_ports()), + ports: Some(service_ports(trino)), selector: Some(role_selector_labels(trino, APP_NAME, &role_name)), type_: Some("NodePort".to_string()), ..ServiceSpec::default() @@ -496,26 +496,9 @@ fn build_rolegroup_statefulset( .add_volume_mount("rwconf", RW_CONFIG_DIR_NAME) .add_volume_mount("keystore", KEYSTORE_DIR_NAME) .add_volume_mount("catalog", format!("{}/catalog", CONFIG_DIR_NAME)) - .add_container_ports(container_ports()) - .readiness_probe(Probe { - initial_delay_seconds: Some(10), - period_seconds: Some(10), - failure_threshold: Some(5), - tcp_socket: Some(TCPSocketAction { - port: IntOrString::String(HTTPS_PORT_NAME.to_string()), - ..TCPSocketAction::default() - }), - ..Probe::default() - }) - .liveness_probe(Probe { - initial_delay_seconds: Some(30), - period_seconds: Some(10), - tcp_socket: Some(TCPSocketAction { - port: IntOrString::String(HTTPS_PORT_NAME.to_string()), - ..TCPSocketAction::default() - }), - ..Probe::default() - }) + .add_container_ports(container_ports(trino)) + .readiness_probe(readiness_probe(trino)) + .liveness_probe(liveness_probe(trino)) .build(); Ok(StatefulSet { metadata: ObjectMetaBuilder::new() @@ -643,7 +626,7 @@ fn build_rolegroup_service( .build(), spec: Some(ServiceSpec { cluster_ip: Some("None".to_string()), - ports: Some(service_ports()), + ports: Some(service_ports(trino)), selector: Some(role_group_selector_labels( trino, APP_NAME, @@ -860,50 +843,60 @@ fn validated_product_config( .context(InvalidProductConfigSnafu) } -fn service_ports() -> Vec { - vec![ +fn service_ports(trino: &TrinoCluster) -> Vec { + let mut ports = vec![ ServicePort { name: Some(HTTP_PORT_NAME.to_string()), port: HTTP_PORT.into(), protocol: Some("TCP".to_string()), ..ServicePort::default() }, - ServicePort { - name: Some(HTTPS_PORT_NAME.to_string()), - port: HTTPS_PORT.into(), - protocol: Some("TCP".to_string()), - ..ServicePort::default() - }, ServicePort { name: Some(METRICS_PORT_NAME.to_string()), port: METRICS_PORT.into(), protocol: Some("TCP".to_string()), ..ServicePort::default() }, - ] + ]; + + if trino.spec.authentication.is_some() { + ports.push(ServicePort { + name: Some(HTTPS_PORT_NAME.to_string()), + port: HTTPS_PORT.into(), + protocol: Some("TCP".to_string()), + ..ServicePort::default() + }); + } + + ports } -fn container_ports() -> Vec { - vec![ +fn container_ports(trino: &TrinoCluster) -> Vec { + let mut ports = vec![ ContainerPort { name: Some(HTTP_PORT_NAME.to_string()), container_port: HTTP_PORT.into(), protocol: Some("TCP".to_string()), ..ContainerPort::default() }, - ContainerPort { - name: Some(HTTPS_PORT_NAME.to_string()), - container_port: HTTPS_PORT.into(), - protocol: Some("TCP".to_string()), - ..ContainerPort::default() - }, ContainerPort { name: Some(METRICS_PORT_NAME.to_string()), container_port: METRICS_PORT.into(), protocol: Some("TCP".to_string()), ..ContainerPort::default() }, - ] + ]; + + if trino.spec.authentication.is_some() { + ports.push(ContainerPort { + name: Some(HTTPS_PORT_NAME.to_string()), + container_port: HTTPS_PORT.into(), + protocol: Some("TCP".to_string()), + ..ContainerPort::default() + }); + } + + ports } fn get_stackable_secret_volume_attributes() -> BTreeMap { @@ -918,3 +911,38 @@ fn get_stackable_secret_volume_attributes() -> BTreeMap { ); result } + +fn readiness_probe(trino: &TrinoCluster) -> Probe { + let port_name = match trino.spec.authentication { + Some(_) => HTTPS_PORT_NAME, + _ => HTTP_PORT_NAME, + }; + + Probe { + initial_delay_seconds: Some(10), + period_seconds: Some(10), + failure_threshold: Some(5), + tcp_socket: Some(TCPSocketAction { + port: IntOrString::String(port_name.to_string()), + ..TCPSocketAction::default() + }), + ..Probe::default() + } +} + +fn liveness_probe(trino: &TrinoCluster) -> Probe { + let port_name = match trino.spec.authentication { + Some(_) => HTTPS_PORT_NAME, + _ => HTTP_PORT_NAME, + }; + + Probe { + initial_delay_seconds: Some(30), + period_seconds: Some(10), + tcp_socket: Some(TCPSocketAction { + port: IntOrString::String(port_name.to_string()), + ..TCPSocketAction::default() + }), + ..Probe::default() + } +} From 68b9d8a06b7579f789d3d052d2c8918e5148e76f Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Thu, 10 Feb 2022 17:32:34 +0100 Subject: [PATCH 03/12] Adapted docs. --- .../trino-operator/configs/properties.yaml | 2 +- deploy/helm/trino-operator/crds/crds.yaml | 30 ++------ docs/modules/ROOT/pages/index.adoc | 2 + docs/modules/ROOT/pages/usage.adoc | 69 ++++++++++++++----- rust/operator-binary/src/controller.rs | 62 +++++++++-------- 5 files changed, 92 insertions(+), 73 deletions(-) diff --git a/deploy/helm/trino-operator/configs/properties.yaml b/deploy/helm/trino-operator/configs/properties.yaml index 43e5e607..8450b4ac 100644 --- a/deploy/helm/trino-operator/configs/properties.yaml +++ b/deploy/helm/trino-operator/configs/properties.yaml @@ -115,7 +115,7 @@ properties: value: "8443" roles: - name: "coordinator" - required: true + required: false asOfVersion: "0.0.0" - property: &queryMaxMemory diff --git a/deploy/helm/trino-operator/crds/crds.yaml b/deploy/helm/trino-operator/crds/crds.yaml index 8e613350..dc18ac2c 100644 --- a/deploy/helm/trino-operator/crds/crds.yaml +++ b/deploy/helm/trino-operator/crds/crds.yaml @@ -201,36 +201,14 @@ spec: required: - roleGroups type: object - hive: + hiveConfigMapName: nullable: true - properties: - chroot: - nullable: true - type: string - name: - type: string - namespace: - nullable: true - type: string - required: - - name - type: object + type: string nodeEnvironment: type: string - opa: + opaConfigMapName: nullable: true - properties: - chroot: - nullable: true - type: string - name: - type: string - namespace: - nullable: true - type: string - required: - - name - type: object + type: string s3: description: Contains all the required connection information for S3. nullable: true diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc index f02b99a9..8afe6b63 100644 --- a/docs/modules/ROOT/pages/index.adoc +++ b/docs/modules/ROOT/pages/index.adoc @@ -10,6 +10,8 @@ The Stackable Operator for Trino currently supports the following versions of Tr include::partial$supported-versions.adoc[] +== Get Docker image + [source] ---- docker pull docker.stackable.tech/stackable/trino: diff --git a/docs/modules/ROOT/pages/usage.adoc b/docs/modules/ROOT/pages/usage.adoc index de14b645..d8565fa4 100644 --- a/docs/modules/ROOT/pages/usage.adoc +++ b/docs/modules/ROOT/pages/usage.adoc @@ -5,11 +5,11 @@ Trino works together with the Apache Hive metastore and S3 bucket. == Prerequisites * Deployed Stackable Apache Hive metastore -* Deployed Stackable https://github.com/stackabletech/secret-operator[secret-operator] * Accessible S3 Bucket ** Endpoint, access-key and secret-key ** Data in the Bucket (we use the https://archive.ics.uci.edu/ml/datasets/iris[Iris] dataset here) -* Optional for authorization: Deployed Stackable OPA cluster + RegoRule server +* Optional deployed Stackable https://github.com/stackabletech/secret-operator[Secret-Operator] for https +* Optional for authorization: Deployed Stackable https://github.com/stackabletech/opa-operator[OPA-Operator] + https://github.com/stackabletech/regorule-operator[Regorule-Operator] * Optional to test queries with https://repo.stackable.tech/#browse/browse:packages:trino-cli%2Ftrino-cli-363-executable.jar[Trino CLI] == Installation @@ -41,11 +41,7 @@ We provide user authentication via secret that can be referred in the custom res namespace: default name: simple-trino-users-secret -These secrets need to be created manually before startup (check `examples/simple-trino-users-secret.yaml`): - - kubectl apply -f examples/simple-trino-users-secret.yaml - -The secret looks the following: +These secrets need to be created manually before startup. The secret may look like the following snippet: apiVersion: v1 kind: Secret @@ -125,7 +121,48 @@ With the prerequisites fulfilled, the CRD for this operator must be created: kubectl apply -f /etc/stackable/trino-operator/crd/trinocluster.crd.yaml -To create a single node Trino (v362) cluster. Please adapt the `s3` with your credentials. +==== Insecure for testing: + +Create an insecure single node Trino (v362) cluster for testing. You will access the UI/CLI via http and no user / password or authorization is required. Please adapt the `s3` settings with your credentials (check `examples/simple-trino-cluster.yaml` for an example setting up Hive and Trino): + + apiVersion: trino.stackable.tech/v1alpha1 + kind: TrinoCluster + metadata: + name: simple-trino + spec: + version: "0.0.362" + nodeEnvironment: production + hiveConfigMapName: simple-hive-derby + s3: + endPoint: changeme + accessKey: changeme + secretKey: changeme + sslEnabled: false + pathStyleAccess: true + coordinators: + roleGroups: + default: + selector: + matchLabels: + kubernetes.io/os: linux + replicas: 1 + config: {} + workers: + roleGroups: + default: + selector: + matchLabels: + kubernetes.io/os: linux + replicas: 1 + config: {} + +To access the CLI please execute: + + ./trino-cli-362-executable.jar --debug --server http://: --user=admin + +==== Secure (https) for production: + +Create a secure single node Trino (v362) cluster. This will disable the UI access via http and requires username and password from the secret above. Please adapt the `s3` settings with your credentials (check `examples/simple-trino-cluster-authentication-opa-authorization.yaml` for a full example setting up Hive, OPA, Secrets and Trino): cat <: --user=admin --password + ./trino-cli-362-executable.jar --debug --server https://: --user=admin --password --insecure If you use self signed certificates, you also need to add `--insecure` to the command above. +=== Test Trino with Hive and S3 + Create a schema and a table for the Iris data located in S3: CREATE SCHEMA IF NOT EXISTS hive.iris @@ -223,6 +258,8 @@ Query the data: FROM hive.iris.iris_parquet LIMIT 10; +=== Tips + If you work with opa, try changing some RegoRule entries to false and see if you are not allowed to e.g. list tables or schemas. When changing the automatically generated rego rule package name, a restart of the coordinator pod is required. \ No newline at end of file diff --git a/rust/operator-binary/src/controller.rs b/rust/operator-binary/src/controller.rs index 47d4716a..851bf6fb 100644 --- a/rust/operator-binary/src/controller.rs +++ b/rust/operator-binary/src/controller.rs @@ -461,23 +461,7 @@ fn build_rolegroup_statefulset( let mut container_prepare = ContainerBuilder::new("prepare") .image(&image) .command(vec!["/bin/bash".to_string(), "-c".to_string()]) - .args(vec![[ - "microdnf install openssl", - "echo Storing password", - "echo secret > /stackable/keystore/password", - "echo Creating truststore", - "keytool -importcert -file /stackable/keystore/ca.crt -keystore /stackable/keystore/truststore.p12 -storetype pkcs12 -noprompt -alias ca_cert -storepass secret", - "echo Creating certificate chain", - "cat /stackable/keystore/ca.crt /stackable/keystore/tls.crt > /stackable/keystore/chain.crt", - "echo Creating keystore", - "openssl pkcs12 -export -in /stackable/keystore/chain.crt -inkey /stackable/keystore/tls.key -out /stackable/keystore/keystore.p12 --passout file:/stackable/keystore/password", - "echo Cleaning up password", - "rm -f /stackable/keystore/password", - "echo chowning keystore directory", - "chown -R stackable:stackable /stackable/keystore", - "echo chmodding keystore directory", - "chmod -R a=,u=rwX /stackable/keystore", - ].join(" && ")]) + .args(container_prepare_args()) .add_volume_mount("keystore", KEYSTORE_DIR_NAME) .build(); @@ -686,6 +670,26 @@ async fn user_authentication( }) } +fn container_prepare_args() -> Vec { + vec![[ + "microdnf install openssl", + "echo Storing password", + "echo secret > /stackable/keystore/password", + "echo Creating truststore", + "keytool -importcert -file /stackable/keystore/ca.crt -keystore /stackable/keystore/truststore.p12 -storetype pkcs12 -noprompt -alias ca_cert -storepass secret", + "echo Creating certificate chain", + "cat /stackable/keystore/ca.crt /stackable/keystore/tls.crt > /stackable/keystore/chain.crt", + "echo Creating keystore", + "openssl pkcs12 -export -in /stackable/keystore/chain.crt -inkey /stackable/keystore/tls.key -out /stackable/keystore/keystore.p12 --passout file:/stackable/keystore/password", + "echo Cleaning up password", + "rm -f /stackable/keystore/password", + "echo chowning keystore directory", + "chown -R stackable:stackable /stackable/keystore", + "echo chmodding keystore directory", + "chmod -R a=,u=rwX /stackable/keystore", + ].join(" && ")] +} + fn container_trino_args( trino: &TrinoCluster, user_authentication: Option, @@ -761,21 +765,19 @@ fn container_trino_args( } fn discovery_config_map(config_map_name: &Option, env_var: &str) -> Option { - match config_map_name { - Some(cm_name) => Some(EnvVar { - name: env_var.to_string(), - value_from: Some(EnvVarSource { - config_map_key_ref: Some(ConfigMapKeySelector { - name: Some(cm_name.to_string()), - key: env_var.to_string(), - ..ConfigMapKeySelector::default() - }), - ..EnvVarSource::default() + config_map_name.as_ref().map(|cm_name| EnvVar { + name: env_var.to_string(), + value_from: Some(EnvVarSource { + config_map_key_ref: Some(ConfigMapKeySelector { + name: Some(cm_name.to_string()), + key: env_var.to_string(), + + ..ConfigMapKeySelector::default() }), - ..EnvVar::default() + ..EnvVarSource::default() }), - None => None, - } + ..EnvVar::default() + }) } /// Defines all required roles and their required configuration. From bdac0ba9acc7409a4129d0550ecec3f8df1b0958 Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Thu, 10 Feb 2022 17:40:10 +0100 Subject: [PATCH 04/12] Adapted CHANGELOG.md --- CHANGELOG.md | 4 +++- rust/crd/src/lib.rs | 9 --------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49fca394..9c5d1729 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ All notable changes to this project will be documented in this file. ### Changed -- BREAKING: `ClusterRef` namespace now optional ([#95]). +- BREAKING: CRD changes. The `spec.opa` and `spec.hive` renamed to `spec.opaConfigMapName` and `spec.hiveConfigMapName` which only accept a String ([#131]). - BREAKING: In case the namespace is omitted, the operator defaults to the `TrinoCluster` namespace instead of `default` ([#95]). - User authentication now provided via secret instead of custom resource ([#81]). - User authentication not exposed in configmap anymore ([#81]). @@ -18,10 +18,12 @@ All notable changes to this project will be documented in this file. - The Trino version is now a string instead of enum ([#81]). - `operator-rs` `0.4.0` → `0.10.0` ([#81], [#95], [#118]). - `stackable-regorule-crd` `0.2.0` → `0.6.0` ([#81], [#118]). +- Improvements to setting up (easy) insecure clusters ([#131]) [#81]: https://github.com/stackabletech/trino-operator/pull/81 [#95]: https://github.com/stackabletech/trino-operator/pull/95 [#118]: https://github.com/stackabletech/trino-operator/pull/118 +[#131]: https://github.com/stackabletech/trino-operator/pull/131 ## [0.2.0] - 2021-12-06 diff --git a/rust/crd/src/lib.rs b/rust/crd/src/lib.rs index f2987ae8..265cb283 100644 --- a/rust/crd/src/lib.rs +++ b/rust/crd/src/lib.rs @@ -198,15 +198,6 @@ impl FromStr for TrinoRole { #[serde(rename_all = "camelCase")] pub struct TrinoClusterStatus {} -// TODO: move to operator-rs? Used for hive, opa, zookeeper ... -#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ClusterRef { - pub name: String, - pub namespace: Option, - pub chroot: Option, -} - // TODO: move to operator-rs? Copied from hive operator. /// Contains all the required connection information for S3. #[derive(Clone, Debug, Default, Deserialize, Eq, Hash, JsonSchema, PartialEq, Serialize)] From 61f1c99efbb92f33f5027b55a6a376919b006c91 Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Thu, 10 Feb 2022 18:28:28 +0100 Subject: [PATCH 05/12] fixed markdown length problem --- CHANGELOG.md | 4 +++- rust/operator-binary/src/controller.rs | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c5d1729..c83f8c36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,9 @@ All notable changes to this project will be documented in this file. ### Changed -- BREAKING: CRD changes. The `spec.opa` and `spec.hive` renamed to `spec.opaConfigMapName` and `spec.hiveConfigMapName` which only accept a String ([#131]). +- BREAKING: CRD changes. The `spec.opa` and `spec.hive` renamed to +`spec.opaConfigMapName` and `spec.hiveConfigMapName` +which only accept a String ([#131]). - BREAKING: In case the namespace is omitted, the operator defaults to the `TrinoCluster` namespace instead of `default` ([#95]). - User authentication now provided via secret instead of custom resource ([#81]). - User authentication not exposed in configmap anymore ([#81]). diff --git a/rust/operator-binary/src/controller.rs b/rust/operator-binary/src/controller.rs index 851bf6fb..1fabffe8 100644 --- a/rust/operator-binary/src/controller.rs +++ b/rust/operator-binary/src/controller.rs @@ -771,7 +771,6 @@ fn discovery_config_map(config_map_name: &Option, env_var: &str) -> Opti config_map_key_ref: Some(ConfigMapKeySelector { name: Some(cm_name.to_string()), key: env_var.to_string(), - ..ConfigMapKeySelector::default() }), ..EnvVarSource::default() From 7a1ddc67287e8284413f2e4332bf811794de51cb Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Thu, 10 Feb 2022 18:30:11 +0100 Subject: [PATCH 06/12] fixed markdown problem #2 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c83f8c36..924e8e3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ All notable changes to this project will be documented in this file. ### Changed -- BREAKING: CRD changes. The `spec.opa` and `spec.hive` renamed to +- BREAKING: CRD changes. The `spec.opa` and `spec.hive` renamed to `spec.opaConfigMapName` and `spec.hiveConfigMapName` which only accept a String ([#131]). - BREAKING: In case the namespace is omitted, the operator defaults to the `TrinoCluster` namespace instead of `default` ([#95]). From ed2d71f0902b14817521c384f824f7ecc8d52ad2 Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Thu, 10 Feb 2022 18:54:11 +0100 Subject: [PATCH 07/12] improved doc highlighting --- docs/modules/ROOT/pages/usage.adoc | 289 +++++++++++++++-------------- 1 file changed, 153 insertions(+), 136 deletions(-) diff --git a/docs/modules/ROOT/pages/usage.adoc b/docs/modules/ROOT/pages/usage.adoc index d8565fa4..e4824efe 100644 --- a/docs/modules/ROOT/pages/usage.adoc +++ b/docs/modules/ROOT/pages/usage.adoc @@ -8,9 +8,9 @@ Trino works together with the Apache Hive metastore and S3 bucket. * Accessible S3 Bucket ** Endpoint, access-key and secret-key ** Data in the Bucket (we use the https://archive.ics.uci.edu/ml/datasets/iris[Iris] dataset here) -* Optional deployed Stackable https://github.com/stackabletech/secret-operator[Secret-Operator] for https -* Optional for authorization: Deployed Stackable https://github.com/stackabletech/opa-operator[OPA-Operator] + https://github.com/stackabletech/regorule-operator[Regorule-Operator] -* Optional to test queries with https://repo.stackable.tech/#browse/browse:packages:trino-cli%2Ftrino-cli-363-executable.jar[Trino CLI] +* Optional deployed Stackable https://github.com/stackabletech/secret-operator[Secret-Operator] for certificates when deploying for HTTPS +* Optional for authorization: Deployed Stackable https://github.com/stackabletech/opa-operator[OPA-Operator] and https://github.com/stackabletech/regorule-operator[Regorule-Operator] +* Optional https://repo.stackable.tech/#browse/browse:packages:trino-cli%2Ftrino-cli-363-executable.jar[Trino CLI] to test SQL queries == Installation @@ -42,20 +42,24 @@ We provide user authentication via secret that can be referred in the custom res name: simple-trino-users-secret These secrets need to be created manually before startup. The secret may look like the following snippet: - - apiVersion: v1 - kind: Secret - metadata: - name: simple-trino-users-secret - type: kubernetes.io/opaque - stringData: - admin: $2y$10$89xReovvDLacVzRGpjOyAOONnayOgDAyIS2nW9bs5DJT98q17Dy5i - alice: $2y$10$HcCa4k9v2DRrD/g7e5vEz.Bk.1xg00YTEHOZjPX7oK3KqMSt2xT8W - bob: $2y$10$xVRXtYZnYuQu66SmruijPO8WHFM/UK5QPHTr.Nzf4JMcZSqt3W.2. +[source,yaml] +---- +apiVersion: v1 +kind: Secret +metadata: + name: simple-trino-users-secret +type: kubernetes.io/opaque +stringData: + admin: $2y$10$89xReovvDLacVzRGpjOyAOONnayOgDAyIS2nW9bs5DJT98q17Dy5i + alice: $2y$10$HcCa4k9v2DRrD/g7e5vEz.Bk.1xg00YTEHOZjPX7oK3KqMSt2xT8W + bob: $2y$10$xVRXtYZnYuQu66SmruijPO8WHFM/UK5QPHTr.Nzf4JMcZSqt3W.2. +---- The : combinations are provided in the `stringData` field. The hashes are created using bcrypt with 10 rounds or more. - - htpasswd -nbBC 10 admin admin +[source] +---- +htpasswd -nbBC 10 admin admin +---- === Regorule Server (Authorization) @@ -65,7 +69,8 @@ Please refer to the https://github.com/stackabletech/regorule-operator[RegoRule] This is an example custom resource for the Stackable RegoRule server: -``` +[source,yaml] +---- apiVersion: opa.stackable.tech/v1alpha1 kind: RegoRule metadata: @@ -111,152 +116,164 @@ spec: } can_view_query_owned_by = true -``` +---- You can let the Trino operator write its own Rego rules by configuring the `authorization` field in the custom resource. This is a rudimentary implementation for user access. === Trino With the prerequisites fulfilled, the CRD for this operator must be created: - - kubectl apply -f /etc/stackable/trino-operator/crd/trinocluster.crd.yaml +[source] +---- +kubectl apply -f /etc/stackable/trino-operator/crd/trinocluster.crd.yaml +---- ==== Insecure for testing: Create an insecure single node Trino (v362) cluster for testing. You will access the UI/CLI via http and no user / password or authorization is required. Please adapt the `s3` settings with your credentials (check `examples/simple-trino-cluster.yaml` for an example setting up Hive and Trino): - - apiVersion: trino.stackable.tech/v1alpha1 - kind: TrinoCluster - metadata: - name: simple-trino - spec: - version: "0.0.362" - nodeEnvironment: production - hiveConfigMapName: simple-hive-derby - s3: - endPoint: changeme - accessKey: changeme - secretKey: changeme - sslEnabled: false - pathStyleAccess: true - coordinators: - roleGroups: - default: - selector: - matchLabels: - kubernetes.io/os: linux - replicas: 1 - config: {} - workers: - roleGroups: - default: - selector: - matchLabels: - kubernetes.io/os: linux - replicas: 1 - config: {} +[source,yaml] +---- +apiVersion: trino.stackable.tech/v1alpha1 +kind: TrinoCluster +metadata: + name: simple-trino +spec: + version: "0.0.362" + nodeEnvironment: production + hiveConfigMapName: simple-hive-derby + s3: + endPoint: changeme + accessKey: changeme + secretKey: changeme + sslEnabled: false + pathStyleAccess: true + coordinators: + roleGroups: + default: + selector: + matchLabels: + kubernetes.io/os: linux + replicas: 1 + config: {} + workers: + roleGroups: + default: + selector: + matchLabels: + kubernetes.io/os: linux + replicas: 1 + config: {} +---- To access the CLI please execute: - - ./trino-cli-362-executable.jar --debug --server http://: --user=admin +[source] +---- +./trino-cli-362-executable.jar --debug --server http://: --user=admin +---- ==== Secure (https) for production: Create a secure single node Trino (v362) cluster. This will disable the UI access via http and requires username and password from the secret above. Please adapt the `s3` settings with your credentials (check `examples/simple-trino-cluster-authentication-opa-authorization.yaml` for a full example setting up Hive, OPA, Secrets and Trino): - cat <: --user=admin --password --insecure +[source] +---- +./trino-cli-362-executable.jar --debug --server https://: --user=admin --password --insecure +---- If you use self signed certificates, you also need to add `--insecure` to the command above. === Test Trino with Hive and S3 Create a schema and a table for the Iris data located in S3: - - CREATE SCHEMA IF NOT EXISTS hive.iris - WITH (location = 's3a://iris/'); - - CREATE TABLE IF NOT EXISTS hive.iris.iris_parquet ( - sepal_length DOUBLE, - sepal_width DOUBLE, - petal_length DOUBLE, - petal_width DOUBLE, - class VARCHAR - ) - WITH ( - external_location = 's3a://iris/parq', - format = 'PARQUET' - ); - +[source,sql] +---- +CREATE SCHEMA IF NOT EXISTS hive.iris +WITH (location = 's3a://iris/'); + +CREATE TABLE IF NOT EXISTS hive.iris.iris_parquet ( + sepal_length DOUBLE, + sepal_width DOUBLE, + petal_length DOUBLE, + petal_width DOUBLE, + class VARCHAR +) +WITH ( + external_location = 's3a://iris/parq', + format = 'PARQUET' +); +---- Query the data: - - SELECT - sepal_length, - class - FROM hive.iris.iris_parquet - LIMIT 10; +[source,sql] +---- +SELECT + sepal_length, + class +FROM hive.iris.iris_parquet +LIMIT 10; +---- === Tips From d7628a6ada00281c8096cd335deae68a2dfc3896 Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Thu, 10 Feb 2022 18:55:41 +0100 Subject: [PATCH 08/12] improved doc highlighting --- docs/modules/ROOT/pages/usage.adoc | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/docs/modules/ROOT/pages/usage.adoc b/docs/modules/ROOT/pages/usage.adoc index e4824efe..2702b4c6 100644 --- a/docs/modules/ROOT/pages/usage.adoc +++ b/docs/modules/ROOT/pages/usage.adoc @@ -33,13 +33,15 @@ Please refer to the https://github.com/stackabletech/opa-operator[OPA] operator === Authentication We provide user authentication via secret that can be referred in the custom resource: - - authentication: - method: - multiUser: - userCredentialsSecret: - namespace: default - name: simple-trino-users-secret +[source,yaml] +---- +authentication: + method: + multiUser: + userCredentialsSecret: + namespace: default + name: simple-trino-users-secret +---- These secrets need to be created manually before startup. The secret may look like the following snippet: [source,yaml] From d1433a064b978a063e9d323a5e2a9d4ad5f6eaf7 Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Thu, 10 Feb 2022 19:02:04 +0100 Subject: [PATCH 09/12] extended docs. --- docs/modules/ROOT/pages/usage.adoc | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/usage.adoc b/docs/modules/ROOT/pages/usage.adoc index 2702b4c6..c2943a17 100644 --- a/docs/modules/ROOT/pages/usage.adoc +++ b/docs/modules/ROOT/pages/usage.adoc @@ -121,6 +121,25 @@ spec: ---- You can let the Trino operator write its own Rego rules by configuring the `authorization` field in the custom resource. This is a rudimentary implementation for user access. +[source,yaml] +---- +authorization: + package: trino + permissions: + admin: + schemas: + read: true + write: true + tables: + iris_parquet: + read: true + write: true + iris_csv: + read: true + write: true +---- + +Here we define permissions for an admin user who can read and write `schemas`, as well as having full access to the `iris_parquet` and `iris_csv` table. Currently, this is more for demonstration purposes. Users should write their own rego rules for more complex OPA authorization. === Trino @@ -245,7 +264,7 @@ To access the CLI please execute: ./trino-cli-362-executable.jar --debug --server https://: --user=admin --password --insecure ---- -If you use self signed certificates, you also need to add `--insecure` to the command above. +If you use self signed certificates, you also need the `--insecure` flag above which can be omitted otherwise. === Test Trino with Hive and S3 From e951b8b24f66353bb9a13ebbcd7bfd432bb3b4c2 Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Thu, 10 Feb 2022 19:09:51 +0100 Subject: [PATCH 10/12] improved docs. --- docs/modules/ROOT/pages/usage.adoc | 45 ++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/docs/modules/ROOT/pages/usage.adoc b/docs/modules/ROOT/pages/usage.adoc index c2943a17..8d8c5ef5 100644 --- a/docs/modules/ROOT/pages/usage.adoc +++ b/docs/modules/ROOT/pages/usage.adoc @@ -268,12 +268,22 @@ If you use self signed certificates, you also need the `--insecure` flag above w === Test Trino with Hive and S3 -Create a schema and a table for the Iris data located in S3: +Create a schema and a table for the Iris data located in S3 and query data. This assumes to have the Iris data set in the `PARQUET` format available in the S3 bucket which can be downloaded https://www.kaggle.com/gpreda/iris-dataset/version/2?select=iris.parquet[here] + +==== Create schema [source,sql] ---- CREATE SCHEMA IF NOT EXISTS hive.iris WITH (location = 's3a://iris/'); +---- +which should return: +---- +CREATE SCHEMA +---- +==== Create table +[source,sql] +---- CREATE TABLE IF NOT EXISTS hive.iris.iris_parquet ( sepal_length DOUBLE, sepal_width DOUBLE, @@ -286,7 +296,12 @@ WITH ( format = 'PARQUET' ); ---- -Query the data: +which should return: +---- +CREATE TABLE +---- + +==== Query data [source,sql] ---- SELECT @@ -296,6 +311,32 @@ FROM hive.iris.iris_parquet LIMIT 10; ---- +which should return something like this: +---- + sepal_length | class +--------------+------------- + 5.1 | Iris-setosa + 4.9 | Iris-setosa + 4.7 | Iris-setosa + 4.6 | Iris-setosa + 5.0 | Iris-setosa + 5.4 | Iris-setosa + 4.6 | Iris-setosa + 5.0 | Iris-setosa + 4.4 | Iris-setosa + 4.9 | Iris-setosa +(10 rows) + +Query 20220210_161615_00000_a8nka, FINISHED, 1 node +https://172.18.0.5:30299/ui/query.html?20220210_161615_00000_a8nka +Splits: 18 total, 18 done (100.00%) +CPU Time: 0.7s total, 20 rows/s, 11.3KB/s, 74% active +Per Node: 0.3 parallelism, 5 rows/s, 3.02KB/s +Parallelism: 0.3 +Peak Memory: 0B +2.67 [15 rows, 8.08KB] [5 rows/s, 3.02KB/s] +---- + === Tips If you work with opa, try changing some RegoRule entries to false and see if you are not allowed to e.g. list tables or schemas. From ce521f3c7a074abeb02a7ef1147997094a74c81b Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Fri, 11 Feb 2022 10:59:35 +0100 Subject: [PATCH 11/12] using tools docker image for init container. removed manually downloading dependencies (openssl) --- rust/operator-binary/src/controller.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/rust/operator-binary/src/controller.rs b/rust/operator-binary/src/controller.rs index 1fabffe8..fc01ad53 100644 --- a/rust/operator-binary/src/controller.rs +++ b/rust/operator-binary/src/controller.rs @@ -434,10 +434,6 @@ fn build_rolegroup_statefulset( .role_groups .get(&rolegroup_ref.role_group); let trino_version = trino_version_trim(trino)?; - let image = format!( - "docker.stackable.tech/stackable/trino:{}-stackable0", - trino_version - ); let mut env = config .get(&PropertyNameKind::Env) @@ -450,16 +446,17 @@ fn build_rolegroup_statefulset( }) .collect::>(); - if let Some(opa) = discovery_config_map(&trino.spec.opa_config_map_name, "OPA") { + if let Some(opa) = env_var_from_discovery_config_map(&trino.spec.opa_config_map_name, "OPA") { env.push(opa); }; - if let Some(hive) = discovery_config_map(&trino.spec.hive_config_map_name, "HIVE") { + if let Some(hive) = env_var_from_discovery_config_map(&trino.spec.hive_config_map_name, "HIVE") + { env.push(hive); }; let mut container_prepare = ContainerBuilder::new("prepare") - .image(&image) + .image("docker.stackable.tech/stackable/tools:0.2.0-stackable0") .command(vec!["/bin/bash".to_string(), "-c".to_string()]) .args(container_prepare_args()) .add_volume_mount("keystore", KEYSTORE_DIR_NAME) @@ -471,7 +468,10 @@ fn build_rolegroup_statefulset( .run_as_user = Some(0); let container_trino = ContainerBuilder::new(APP_NAME) - .image(image) + .image(format!( + "docker.stackable.tech/stackable/trino:{}-stackable0", + trino_version + )) .command(vec!["/bin/bash".to_string(), "-c".to_string()]) .args(container_trino_args(trino, authentication_config)) .add_env_vars(env) @@ -672,9 +672,10 @@ async fn user_authentication( fn container_prepare_args() -> Vec { vec![[ - "microdnf install openssl", "echo Storing password", "echo secret > /stackable/keystore/password", + "echo Cleaning up truststore - just in case", + "rm -f /stackable/keystore/truststore.p12", "echo Creating truststore", "keytool -importcert -file /stackable/keystore/ca.crt -keystore /stackable/keystore/truststore.p12 -storetype pkcs12 -noprompt -alias ca_cert -storepass secret", "echo Creating certificate chain", @@ -764,7 +765,10 @@ fn container_trino_args( vec![args.join(" && ")] } -fn discovery_config_map(config_map_name: &Option, env_var: &str) -> Option { +fn env_var_from_discovery_config_map( + config_map_name: &Option, + env_var: &str, +) -> Option { config_map_name.as_ref().map(|cm_name| EnvVar { name: env_var.to_string(), value_from: Some(EnvVarSource { From e91ff574df10d7adb45068ee630ec6fb1d662b4b Mon Sep 17 00:00:00 2001 From: Malte Sander Date: Fri, 11 Feb 2022 13:07:59 +0100 Subject: [PATCH 12/12] regenerated manifests. --- deploy/manifests/configmap.yaml | 2 +- deploy/manifests/crds.yaml | 30 ++++-------------------------- 2 files changed, 5 insertions(+), 27 deletions(-) diff --git a/deploy/manifests/configmap.yaml b/deploy/manifests/configmap.yaml index e1ad0903..e5212f96 100644 --- a/deploy/manifests/configmap.yaml +++ b/deploy/manifests/configmap.yaml @@ -39,7 +39,7 @@ data: \ file: \"config.properties\"\n datatype:\n type: \"integer\"\n \ min: \"1024\"\n max: \"65535\"\n defaultValues:\n - fromVersion: \"0.0.0\"\n value: \"8443\"\n roles:\n - name: \"coordinator\"\n - \ required: true\n asOfVersion: \"0.0.0\"\n\n - property: &queryMaxMemory\n + \ required: false\n asOfVersion: \"0.0.0\"\n\n - property: &queryMaxMemory\n \ propertyNames:\n - name: \"query.max-memory\"\n kind:\n type: \"file\"\n file: \"config.properties\"\n datatype:\n type: \"string\"\n unit: *unitMemory\n defaultValues:\n - fromVersion: diff --git a/deploy/manifests/crds.yaml b/deploy/manifests/crds.yaml index 53e85339..a7cfa456 100644 --- a/deploy/manifests/crds.yaml +++ b/deploy/manifests/crds.yaml @@ -203,36 +203,14 @@ spec: required: - roleGroups type: object - hive: + hiveConfigMapName: nullable: true - properties: - chroot: - nullable: true - type: string - name: - type: string - namespace: - nullable: true - type: string - required: - - name - type: object + type: string nodeEnvironment: type: string - opa: + opaConfigMapName: nullable: true - properties: - chroot: - nullable: true - type: string - name: - type: string - namespace: - nullable: true - type: string - required: - - name - type: object + type: string s3: description: Contains all the required connection information for S3. nullable: true