Skip to content

Commit 5b4c063

Browse files
authored
feat: Add Airflow 3.2.1 (#803)
* test: Add Airflow 3.2.1 Note: The metrics test broke because airflow no longer exports metrics from the webserver role. Instead, we check completion via the API. * chore(nix): add grpcurl Used for interacting with Vector API. Likely not needed, but handy if debugging the vector-aggregator tests for new versions. * chore(nix): Formatting * docs(supported-versions): Add 3.2.1, deprecate 3.1.6 * test: Update assertions Airflow 3.2 changes "migrating" to "migration" * test: Increase schedule memory limit Keeps getting OOMKilled in the logging test since Airflow 3.2 * test(common/metrics): Check dag started via the web API. Later versions of Airflow don't emit metrics from the web server. These tests also never waited for a success, only checked creation. So that remains for now, and could be improved later. * docs(getting_started): Bump to Airflow 3.2.1 * docs: Bump postgres requirement to 17 I removed 12, even though it is supported by older versions that we support. * revert(nix): Restore shell.nix This file is templated from https://github.com/stackabletech/operator-templating/blob/main/template/shell.nix
1 parent 25b84b6 commit 5b4c063

9 files changed

Lines changed: 62 additions & 41 deletions

File tree

docs/modules/airflow/examples/getting_started/code/airflow.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ metadata:
55
name: airflow
66
spec:
77
image:
8-
productVersion: 3.1.6
8+
productVersion: 3.2.1
99
pullPolicy: IfNotPresent
1010
clusterConfig:
1111
loadExamples: true

docs/modules/airflow/pages/required-external-components.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ The {airflow-prerequisites}[Airflow documentation] specifies:
77

88
Fully supported for production usage:
99

10-
* PostgreSQL: 12, 13, 14, 15, 16
10+
* PostgreSQL: 13, 14, 15, 16, 17
1111
1212
NOTE: The SDP Airflow images do not bundle the MySQL provider for Airflow.
1313
If you need MySQL or MariaDB as an Airflow back-end, you will need to create a custom image to include this provider.

docs/modules/airflow/partials/supported-versions.adoc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// This is a separate file, since it is used by both the direct Airflow-Operator documentation, and the overarching
33
// Stackable Platform documentation.
44

5-
- 3.1.6
5+
- 3.2.1
6+
- 3.1.6 (deprecated)
67
- 3.0.6 (LTS)
78
- 2.9.3 (deprecated)

tests/templates/kuttl/cluster-operation/09-assert.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ kind: TestAssert
55
timeout: 30
66
commands:
77
- script: |
8-
kubectl -n $NAMESPACE logs airflow-scheduler-default-0 | grep "Database migrating done!"
8+
kubectl -n $NAMESPACE logs airflow-scheduler-default-0 | grep -E "Database migrat(ing|ion) done!"

tests/templates/kuttl/cluster-operation/31-assert.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ kind: TestAssert
55
timeout: 30
66
commands:
77
- script: |
8-
kubectl -n $NAMESPACE logs airflow-scheduler-default-0 | grep "Database migrating done!" && exit 1 || exit 0
8+
kubectl -n $NAMESPACE logs airflow-scheduler-default-0 | grep -E "Database migrat(ing|ion) done!" && exit 1 || exit 0

tests/templates/kuttl/commons/metrics.py

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,22 @@ def assert_metric(role, role_group, metric):
2525
return metric in metric_response.text
2626

2727

28+
# Check if dag run state is "success", "queued", or "running"
29+
# TODO: in future, we could wait on it.
30+
# See: https://airflow.apache.org/docs/apache-airflow/3.1.6/stable-rest-api-ref.html#operation/wait_dag_run_until_finished
31+
def assert_dag_started(rest_url, headers, dag_id, dag_run_id):
32+
dag_run_response = requests.get(
33+
f"{rest_url}/dags/{dag_id}/dagRuns/{dag_run_id}", headers=headers
34+
)
35+
dag_run_state = dag_run_response.json()["state"]
36+
print(f"DAG RUN STATE: {dag_run_state}")
37+
return (
38+
dag_run_state == "success"
39+
or dag_run_state == "queued"
40+
or dag_run_state == "running"
41+
)
42+
43+
2844
def metrics_v3(role_group: str) -> None:
2945
now = datetime.now(timezone.utc)
3046
ts = now.strftime("%Y-%m-%dT%H:%M:%S.%f") + now.strftime("%z")
@@ -66,10 +82,14 @@ def metrics_v3(role_group: str) -> None:
6682
response = requests.patch(
6783
f"{rest_url}/dags/{dag_id}", headers=headers, json={"is_paused": False}
6884
)
85+
6986
# trigger DAG
7087
response = requests.post(
7188
f"{rest_url}/dags/{dag_id}/dagRuns", headers=headers, json=dag_data
7289
)
90+
dag_run_id = response.json()["dag_run_id"]
91+
92+
print(f"DAG RUN ID: {dag_run_id}")
7393

7494
# Test the DAG in a loop. Each time we call the script a new job will be started: we can avoid
7595
# or minimize this by looping over the check instead.
@@ -79,24 +99,13 @@ def metrics_v3(role_group: str) -> None:
7999
assert response.status_code == 200, "DAG run could not be triggered."
80100
# Wait for the metrics to be consumed by the statsd-exporter
81101
time.sleep(5)
82-
# (disable line-break flake checks)
102+
heartbeat_metric = "airflow_scheduler_heartbeat"
103+
dag_run_success_count_metric = f"airflow_dagrun_duration_success_{dag_id}_count"
83104
if (
84-
(assert_metric("scheduler", role_group, "airflow_scheduler_heartbeat"))
85-
and (
86-
assert_metric(
87-
"webserver",
88-
role_group,
89-
"airflow_task_instance_created_BashOperator",
90-
)
91-
) # noqa: W503, W504
92-
and (
93-
assert_metric(
94-
"scheduler",
95-
role_group,
96-
"airflow_dagrun_duration_success_example_trigger_target_dag_count",
97-
)
98-
)
99-
): # noqa: W503, W504
105+
assert_dag_started(rest_url, headers, dag_id, dag_run_id)
106+
and assert_metric("scheduler", role_group, heartbeat_metric)
107+
and assert_metric("scheduler", role_group, dag_run_success_count_metric)
108+
):
100109
break
101110
time.sleep(10)
102111
loop += 1

tests/templates/kuttl/logging/41-install-airflow-cluster.yaml.j2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ spec:
271271
min: 1000m
272272
max: 2000m
273273
memory:
274-
limit: 1Gi
274+
limit: 2Gi
275275
roleGroups:
276276
automatic-log-config:
277277
replicas: 1

tests/templates/kuttl/triggerer/triggerer_metrics.py

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,22 @@ def assert_metric(role, role_group, metric):
2525
return metric in metric_response.text
2626

2727

28+
# Check if dag run state is "success", "queued", or "running"
29+
# TODO: in future, we could wait on it.
30+
# See: https://airflow.apache.org/docs/apache-airflow/3.1.6/stable-rest-api-ref.html#operation/wait_dag_run_until_finished
31+
def assert_dag_started(rest_url, headers, dag_id, dag_run_id):
32+
dag_run_response = requests.get(
33+
f"{rest_url}/dags/{dag_id}/dagRuns/{dag_run_id}", headers=headers
34+
)
35+
dag_run_state = dag_run_response.json()["state"]
36+
print(f"DAG RUN STATE: {dag_run_state}")
37+
return (
38+
dag_run_state == "success"
39+
or dag_run_state == "queued"
40+
or dag_run_state == "running"
41+
)
42+
43+
2844
def metrics_v3(role_group: str) -> None:
2945
now = datetime.now(timezone.utc)
3046
ts = now.strftime("%Y-%m-%dT%H:%M:%S.%f") + now.strftime("%z")
@@ -64,11 +80,16 @@ def metrics_v3(role_group: str) -> None:
6480
response = requests.patch(
6581
f"{rest_url}/dags/{dag_id}", headers=headers, json={"is_paused": False}
6682
)
83+
6784
# trigger DAG
6885
response = requests.post(
6986
f"{rest_url}/dags/{dag_id}/dagRuns", headers=headers, json=dag_data
7087
)
7188

89+
dag_run_id = response.json()["dag_run_id"]
90+
91+
print(f"DAG RUN ID: {dag_run_id}")
92+
7293
# Test the DAG in a loop. Each time we call the script a new job will be started: we can avoid
7394
# or minimize this by looping over the check instead.
7495
iterations = 4
@@ -77,24 +98,13 @@ def metrics_v3(role_group: str) -> None:
7798
assert response.status_code == 200, "DAG run could not be triggered."
7899
# Wait for the metrics to be consumed by the statsd-exporter
79100
time.sleep(5)
80-
# (disable line-break flake checks)
101+
heartbeat_metric = "airflow_scheduler_heartbeat"
102+
dag_run_success_count_metric = f"airflow_dagrun_duration_success_{dag_id}_count"
81103
if (
82-
(assert_metric("scheduler", role_group, "airflow_scheduler_heartbeat"))
83-
and (
84-
assert_metric(
85-
"webserver",
86-
role_group,
87-
"airflow_task_instance_created_CoreDeferrableSleepOperator",
88-
)
89-
) # noqa: W503, W504
90-
and (
91-
assert_metric(
92-
"scheduler",
93-
role_group,
94-
"airflow_dagrun_duration_success_core_deferrable_sleep_demo_count",
95-
)
96-
)
97-
): # noqa: W503, W504
104+
assert_dag_started(rest_url, headers, dag_id, dag_run_id)
105+
and assert_metric("scheduler", role_group, heartbeat_metric)
106+
and assert_metric("scheduler", role_group, dag_run_success_count_metric)
107+
):
98108
break
99109
time.sleep(10)
100110
loop += 1

tests/test-definition.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ dimensions:
1010
- 2.9.3
1111
- 3.0.6
1212
- 3.1.6
13+
- 3.2.1
1314
# To use a custom image, add a comma and the full name after the product version
1415
# - x.x.x,oci.stackable.tech/sandbox/airflow:x.x.x-stackable0.0.0-dev
1516
- name: airflow-latest
1617
values:
17-
- 3.1.6
18+
- 3.2.1
1819
# To use a custom image, add a comma and the full name after the product version
1920
# - x.x.x,oci.stackable.tech/sandbox/airflow:x.x.x-stackable0.0.0-dev
2021
- name: opa-latest

0 commit comments

Comments
 (0)