Skip to content

Commit e8cdf10

Browse files
Malewaresbernauer
andauthored
Allow arbitrary python code (#493)
* Bumping operator-rs to 0.74.0 * Adding docs * Allow arbitrary python code with Footer and Header keys * Update Changelog * Adding some tests for new file vars * Reworking tests, green now * Code Review Co-authored-by: Sebastian Bernauer <sebastian.bernauer@stackable.de> --------- Co-authored-by: Sebastian Bernauer <sebastian.bernauer@stackable.de>
1 parent 5cb377b commit e8cdf10

File tree

5 files changed

+77
-1
lines changed

5 files changed

+77
-1
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## [Unreleased]
44

5+
### Added
6+
7+
- Allowing arbitrary python code as `EXPERIMENTAL_FILE_HEADER` and `EXPERIMENTAL_FILE_FOOTER` in `webserver_config.py` ([#493]).
8+
59
### Changed
610

711
- Reduce CRD size from `1.7MB` to `111KB` by accepting arbitrary YAML input instead of the underlying schema for the following fields ([#488]):
@@ -16,6 +20,7 @@
1620

1721
[#488]: https://github.com/stackabletech/airflow-operator/pull/488
1822
[#489]: https://github.com/stackabletech/airflow-operator/pull/489
23+
[#493]: https://github.com/stackabletech/airflow-operator/pull/493
1924

2025
## [24.7.0] - 2024-07-24
2126

docs/modules/airflow/pages/usage-guide/overrides.adoc

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,33 @@ that each component has the same configuration: not all components use each sett
1010

1111
Airflow exposes an environment variable for every Airflow configuration setting, a list of which can be found in the https://airflow.apache.org/docs/apache-airflow/stable/configurations-ref.html[Configuration Reference].
1212

13+
As Airflow can be configured with python code too, arbitrary code can be added to the `webserver_config.py`.
14+
You can use either `EXPERIMENTAL_FILE_HEADER` to add code to the top or `EXPERIMENTAL_FILE_FOOTER` to add to the bottom.
15+
16+
IMPORTANT: This is an experimental feature
17+
18+
[source,yaml]
19+
----
20+
webservers:
21+
configOverrides:
22+
webserver_config.py:
23+
CSV_EXPORT: "{'encoding': 'utf-8'}"
24+
EXPERIMENTAL_FILE_HEADER: |
25+
from modules.my_module import my_class
26+
EXPERIMENTAL_FILE_FOOTER: |
27+
import logging
28+
from airflow.security import AirflowSecurityManager
29+
30+
class myCustomSecurityManger(AirflowSecurityManager):
31+
def __init__():
32+
init()
33+
34+
CUSTOM_SECURITY_MANAGER = myCustomSecurityManger
35+
roleGroups:
36+
default:
37+
config: {}
38+
----
39+
1340
Although Kubernetes can override these settings in one of two ways (Configuration overrides, or Environment Variable overrides), the affect is the same
1441
and currently only the latter is implemented. This is described in the following section.
1542

rust/operator-binary/src/airflow_controller.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,10 @@ use stackable_operator::{
5050
},
5151
kvp::{Label, LabelError, Labels},
5252
logging::controller::ReconcilerError,
53-
product_config_utils::{transform_all_roles_to_config, validate_all_roles_and_groups_config},
53+
product_config_utils::{
54+
transform_all_roles_to_config, validate_all_roles_and_groups_config,
55+
CONFIG_OVERRIDE_FILE_FOOTER_KEY, CONFIG_OVERRIDE_FILE_HEADER_KEY,
56+
},
5457
product_logging::{
5558
self,
5659
spec::{ContainerLogConfig, Logging},
@@ -65,6 +68,7 @@ use stackable_operator::{
6568
};
6669
use std::{
6770
collections::{BTreeMap, HashMap},
71+
io::Write,
6872
str::FromStr,
6973
sync::Arc,
7074
};
@@ -280,6 +284,11 @@ pub enum Error {
280284

281285
#[snafu(display("failed to construct config"))]
282286
ConstructConfig { source: config::Error },
287+
288+
#[snafu(display(
289+
"failed to write to String (Vec<u8> to be precise) containing Airflow config"
290+
))]
291+
WriteToConfigFileString { source: std::io::Error },
283292
}
284293

285294
type Result<T, E = Error> = std::result::Result<T, E>;
@@ -639,6 +648,15 @@ fn build_rolegroup_config_map(
639648
config::add_airflow_config(&mut config, authentication_config).context(ConstructConfigSnafu)?;
640649

641650
let mut config_file = Vec::new();
651+
652+
// By removing the keys from `config_properties`, we avoid pasting the Python code into a Python variable as well
653+
// (which would be bad)
654+
if let Some(header) = config.remove(CONFIG_OVERRIDE_FILE_HEADER_KEY) {
655+
writeln!(config_file, "{}", header).context(WriteToConfigFileStringSnafu)?;
656+
}
657+
658+
let temp_file_footer: Option<String> = config.remove(CONFIG_OVERRIDE_FILE_FOOTER_KEY);
659+
642660
flask_app_config_writer::write::<AirflowConfigOptions, _, _>(
643661
&mut config_file,
644662
config.iter(),
@@ -648,6 +666,10 @@ fn build_rolegroup_config_map(
648666
rolegroup: rolegroup.clone(),
649667
})?;
650668

669+
if let Some(footer) = temp_file_footer {
670+
writeln!(config_file, "{}", footer).context(WriteToConfigFileStringSnafu)?;
671+
}
672+
651673
let mut cm_builder = ConfigMapBuilder::new();
652674

653675
cm_builder

tests/templates/kuttl/smoke/40-install-airflow-cluster.yaml.j2

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,20 @@ spec:
4545
config:
4646
logging:
4747
enableVectorAgent: {{ lookup('env', 'VECTOR_AGGREGATOR') | length > 0 }}
48+
configOverrides:
49+
webserver_config.py:
50+
EXPERIMENTAL_FILE_HEADER: |
51+
COMMON_HEADER_VAR = "role-value"
52+
ROLE_HEADER_VAR = "role-value"
53+
EXPERIMENTAL_FILE_FOOTER: |
54+
ROLE_FOOTER_VAR = "role-value"
4855
roleGroups:
4956
default:
5057
replicas: 1
58+
configOverrides:
59+
webserver_config.py:
60+
EXPERIMENTAL_FILE_HEADER: |
61+
COMMON_HEADER_VAR = "group-value"
5162
{% if test_scenario['values']['executor'] == 'celery' %}
5263
celeryExecutors:
5364
config:
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: 600
5+
commands:
6+
#
7+
# Test envOverrides
8+
#
9+
- script: |
10+
kubectl -n $NAMESPACE get cm airflow-webserver-default -o yaml | yq -e '.data."webserver_config.py"' | grep "COMMON_HEADER_VAR = \"group-value\""
11+
kubectl -n $NAMESPACE get cm airflow-webserver-default -o yaml | yq -e '.data."webserver_config.py"' | grep "ROLE_FOOTER_VAR = \"role-value\""

0 commit comments

Comments
 (0)