Skip to content

Commit cd52d4a

Browse files
authored
fix: Remote logging in Airflow 3.x (#683)
* adapt custom logging to resolve RemoteLogIO handler * switch logic branches so that change extends beyond 3.x * fixed version match * integration test * changelog, cleaned up minio install
1 parent bfe02aa commit cd52d4a

25 files changed

+724
-6
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@
1313
- Allow multiple Airflows in the same namespace to use Kubernetes executors.
1414
Previously, the operator would always use the same name for the executor Pod template ConfigMap.
1515
Thus when deploying multiple Airflow instances in the same namespace, there would be a conflict over the contents of that ConfigMap ([#678]).
16+
- For versions >= 3 custom logging initializes the RemoteLogIO handler to fix remote logging ([#683]).
1617

1718
[#667]: https://github.com/stackabletech/airflow-operator/pull/667
1819
[#668]: https://github.com/stackabletech/airflow-operator/pull/668
1920
[#669]: https://github.com/stackabletech/airflow-operator/pull/669
2021
[#678]: https://github.com/stackabletech/airflow-operator/pull/678
22+
[#683]: https://github.com/stackabletech/airflow-operator/pull/683
2123

2224
## [25.7.0] - 2025-07-23
2325

rust/operator-binary/src/airflow_controller.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -806,6 +806,7 @@ fn build_rolegroup_config_map(
806806
container,
807807
&Container::Vector,
808808
&mut cm_builder,
809+
resolved_product_image,
809810
)
810811
.context(InvalidLoggingConfigSnafu {
811812
cm_name: rolegroup.object_name(),

rust/operator-binary/src/product_logging.rs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::fmt::{Display, Write};
33
use snafu::Snafu;
44
use stackable_operator::{
55
builder::configmap::ConfigMapBuilder,
6+
commons::product_image_selection::ResolvedProductImage,
67
kube::Resource,
78
product_logging::{
89
self,
@@ -43,6 +44,7 @@ pub fn extend_config_map_with_log_config<C, K>(
4344
main_container: &C,
4445
vector_container: &C,
4546
cm_builder: &mut ConfigMapBuilder,
47+
resolved_product_image: &ResolvedProductImage,
4648
) -> Result<()>
4749
where
4850
C: Clone + Ord + Display,
@@ -53,7 +55,10 @@ where
5355
}) = logging.containers.get(main_container)
5456
{
5557
let log_dir = format!("{STACKABLE_LOG_DIR}/{main_container}");
56-
cm_builder.add_data(LOG_CONFIG_FILE, create_airflow_config(log_config, &log_dir));
58+
cm_builder.add_data(
59+
LOG_CONFIG_FILE,
60+
create_airflow_config(log_config, &log_dir, resolved_product_image),
61+
);
5762
}
5863

5964
let vector_log_config = if let Some(ContainerLogConfig {
@@ -75,7 +80,11 @@ where
7580
Ok(())
7681
}
7782

78-
fn create_airflow_config(log_config: &AutomaticContainerLogConfig, log_dir: &str) -> String {
83+
fn create_airflow_config(
84+
log_config: &AutomaticContainerLogConfig,
85+
log_dir: &str,
86+
resolved_product_image: &ResolvedProductImage,
87+
) -> String {
7988
let loggers_config = log_config
8089
.loggers
8190
.iter()
@@ -92,18 +101,28 @@ LOGGING_CONFIG['loggers']['{name}']['level'] = {level}
92101
output
93102
});
94103

104+
let remote_task_log = if resolved_product_image.product_version.starts_with("2.") {
105+
""
106+
} else {
107+
"
108+
# This will cause the relevant RemoteLogIO handler to be initialized
109+
REMOTE_TASK_LOG = airflow_local_settings.REMOTE_TASK_LOG
110+
log = logging.getLogger(__name__)
111+
log.info('Custom logging remote task log %s', REMOTE_TASK_LOG)
112+
"
113+
};
114+
95115
format!(
96116
"\
97117
import logging
98118
import os
99119
from copy import deepcopy
100-
from airflow.config_templates.airflow_local_settings import DEFAULT_LOGGING_CONFIG
120+
from airflow.config_templates import airflow_local_settings
101121
102122
os.makedirs('{log_dir}', exist_ok=True)
103123
104-
LOGGING_CONFIG = deepcopy(DEFAULT_LOGGING_CONFIG)
105-
106-
REMOTE_TASK_LOG = None
124+
LOGGING_CONFIG = deepcopy(airflow_local_settings.DEFAULT_LOGGING_CONFIG)
125+
{remote_task_log}
107126
108127
LOGGING_CONFIG.setdefault('loggers', {{}})
109128
for logger_name, logger_config in LOGGING_CONFIG['loggers'].items():
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{% if test_scenario['values']['openshift'] == 'true' %}
2+
# see https://github.com/stackabletech/issues/issues/566
3+
---
4+
apiVersion: kuttl.dev/v1beta1
5+
kind: TestStep
6+
commands:
7+
- script: kubectl patch namespace $NAMESPACE -p '{"metadata":{"labels":{"pod-security.kubernetes.io/enforce":"privileged"}}}'
8+
timeout: 120
9+
{% endif %}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{% if test_scenario['values']['executor'] == 'celery' %}
2+
---
3+
apiVersion: v1
4+
kind: LimitRange
5+
metadata:
6+
name: limit-request-ratio
7+
spec:
8+
limits:
9+
- type: "Container"
10+
maxLimitRequestRatio:
11+
cpu: 5
12+
memory: 1
13+
{% endif %}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
apiVersion: v1
3+
kind: Secret
4+
metadata:
5+
name: minio-credentials
6+
labels:
7+
secrets.stackable.tech/class: spark-pi-private-s3-credentials-class
8+
timeout: 240
9+
stringData:
10+
accessKey: minioAccessKey
11+
secretKey: minioSecretKey
12+
# The following two entries are used by the Bitnami chart for MinIO to
13+
# set up credentials for accessing buckets managed by the MinIO tenant.
14+
root-user: minioAccessKey
15+
root-password: minioSecretKey
16+
---
17+
apiVersion: secrets.stackable.tech/v1alpha1
18+
kind: SecretClass
19+
metadata:
20+
name: spark-pi-private-s3-credentials-class
21+
spec:
22+
backend:
23+
k8sSearch:
24+
searchNamespace:
25+
pod: {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
apiVersion: kuttl.dev/v1beta1
3+
kind: TestAssert
4+
timeout: 900
5+
---
6+
apiVersion: apps/v1
7+
kind: Deployment
8+
metadata:
9+
name: test-minio
10+
status:
11+
readyReplicas: 1
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
apiVersion: kuttl.dev/v1beta1
3+
kind: TestStep
4+
commands:
5+
- script: >-
6+
helm install test-minio
7+
--namespace $NAMESPACE
8+
--version 17.0.19
9+
-f helm-bitnami-minio-values.yaml
10+
oci://registry-1.docker.io/bitnamicharts/minio
11+
timeout: 240
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
apiVersion: kuttl.dev/v1beta1
3+
kind: TestAssert
4+
metadata:
5+
name: test-airflow-postgresql
6+
timeout: 480
7+
---
8+
apiVersion: apps/v1
9+
kind: StatefulSet
10+
metadata:
11+
name: airflow-postgresql
12+
status:
13+
readyReplicas: 1
14+
replicas: 1
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
apiVersion: kuttl.dev/v1beta1
3+
kind: TestStep
4+
commands:
5+
- script: >-
6+
helm install airflow-postgresql
7+
--namespace $NAMESPACE
8+
--version 16.4.2
9+
-f helm-bitnami-postgresql-values.yaml
10+
oci://registry-1.docker.io/bitnamicharts/postgresql
11+
--wait
12+
timeout: 600

0 commit comments

Comments
 (0)