Skip to content

Commit 440c9eb

Browse files
authored
Fixup system test for DataprocSubmitJobOperator (PySpark job) (#32740)
1 parent 4992176 commit 440c9eb

2 files changed

Lines changed: 56 additions & 15 deletions

File tree

airflow/providers/google/cloud/operators/dataproc.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1504,6 +1504,10 @@ def execute(self, context: Context):
15041504
class DataprocSubmitPySparkJobOperator(DataprocJobBaseOperator):
15051505
"""Start a PySpark Job on a Cloud DataProc cluster.
15061506
1507+
.. seealso::
1508+
This operator is deprecated, please use
1509+
:class:`~airflow.providers.google.cloud.operators.dataproc.DataprocSubmitJobOperator`:
1510+
15071511
:param main: [Required] The Hadoop Compatible Filesystem (HCFS) URI of the main
15081512
Python file to use as the driver. Must be a .py file. (templated)
15091513
:param arguments: Arguments for the job. (templated)
@@ -1940,7 +1944,7 @@ class DataprocSubmitJobOperator(GoogleCloudBaseOperator):
19401944
:param job: Required. The job resource.
19411945
If a dict is provided, it must be of the same form as the protobuf message
19421946
:class:`~google.cloud.dataproc_v1.types.Job`.
1943-
For the complete list of supported job types please take a look here
1947+
For the complete list of supported job types and their configurations please take a look here
19441948
https://cloud.google.com/dataproc/docs/reference/rest/v1/projects.regions.jobs
19451949
:param request_id: Optional. A unique id used to identify the request. If the server receives two
19461950
``SubmitJobRequest`` requests with the same id, then the second request will be ignored and the first

tests/system/providers/google/cloud/dataproc/example_dataproc_pyspark.py

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,18 @@
2222

2323
import os
2424
from datetime import datetime
25-
from pathlib import Path
2625

2726
from airflow import models
27+
from airflow.decorators import task
2828
from airflow.providers.google.cloud.operators.dataproc import (
2929
DataprocCreateClusterOperator,
3030
DataprocDeleteClusterOperator,
3131
DataprocSubmitJobOperator,
3232
)
33-
from airflow.providers.google.cloud.operators.gcs import GCSCreateBucketOperator, GCSDeleteBucketOperator
33+
from airflow.providers.google.cloud.operators.gcs import (
34+
GCSCreateBucketOperator,
35+
GCSDeleteBucketOperator,
36+
)
3437
from airflow.providers.google.cloud.transfers.local_to_gcs import LocalFilesystemToGCSOperator
3538
from airflow.utils.trigger_rule import TriggerRule
3639

@@ -43,11 +46,7 @@
4346
REGION = "europe-west1"
4447
ZONE = "europe-west1-b"
4548

46-
PYSPARK_SRC = str(Path(__file__).parent / "resources" / "hello_world.py")
47-
PYSPARK_FILE = "hello_world.py"
48-
4949
# Cluster definition
50-
5150
CLUSTER_CONFIG = {
5251
"master_config": {
5352
"num_instances": 1,
@@ -61,14 +60,35 @@
6160
},
6261
}
6362

64-
TIMEOUT = {"seconds": 1 * 24 * 60 * 60}
63+
JOB_FILE_NAME = "dataproc-pyspark-job.py"
64+
JOB_FILE_LOCAL_PATH = f"/tmp/{JOB_FILE_NAME}"
65+
JOB_FILE_CONTENT = """from operator import add
66+
from random import random
67+
68+
from pyspark.sql import SparkSession
69+
70+
71+
def f(_: int) -> float:
72+
x = random() * 2 - 1
73+
y = random() * 2 - 1
74+
return 1 if x**2 + y**2 <= 1 else 0
75+
76+
77+
spark = SparkSession.builder.appName("PythonPi").getOrCreate()
78+
partitions = 2
79+
n = 100000 * partitions
80+
count = spark.sparkContext.parallelize(range(1, n + 1), partitions).map(f).reduce(add)
81+
print(f"Pi is roughly {4.0 * count / n:f}")
82+
83+
spark.stop()
84+
"""
6585

6686
# Jobs definitions
6787
# [START how_to_cloud_dataproc_pyspark_config]
6888
PYSPARK_JOB = {
6989
"reference": {"project_id": PROJECT_ID},
7090
"placement": {"cluster_name": CLUSTER_NAME},
71-
"pyspark_job": {"main_python_file_uri": f"gs://{BUCKET_NAME}/{PYSPARK_FILE}"},
91+
"pyspark_job": {"main_python_file_uri": f"gs://{BUCKET_NAME}/{JOB_FILE_NAME}"},
7292
}
7393
# [END how_to_cloud_dataproc_pyspark_config]
7494

@@ -78,15 +98,23 @@
7898
schedule="@once",
7999
start_date=datetime(2021, 1, 1),
80100
catchup=False,
81-
tags=["example", "dataproc"],
101+
tags=["example", "dataproc", "pyspark"],
82102
) as dag:
83103
create_bucket = GCSCreateBucketOperator(
84104
task_id="create_bucket", bucket_name=BUCKET_NAME, project_id=PROJECT_ID
85105
)
106+
107+
@task
108+
def create_job_file():
109+
with open(JOB_FILE_LOCAL_PATH, "w") as job_file:
110+
job_file.write(JOB_FILE_CONTENT)
111+
112+
create_job_file_task = create_job_file()
113+
86114
upload_file = LocalFilesystemToGCSOperator(
87115
task_id="upload_file",
88-
src=PYSPARK_SRC,
89-
dst=PYSPARK_FILE,
116+
src=JOB_FILE_LOCAL_PATH,
117+
dst=JOB_FILE_NAME,
90118
bucket=BUCKET_NAME,
91119
)
92120

@@ -116,14 +144,23 @@
116144
task_id="delete_bucket", bucket_name=BUCKET_NAME, trigger_rule=TriggerRule.ALL_DONE
117145
)
118146

147+
@task(trigger_rule=TriggerRule.ALL_DONE)
148+
def delete_job_file():
149+
try:
150+
os.remove(JOB_FILE_LOCAL_PATH)
151+
except FileNotFoundError:
152+
pass
153+
return 0
154+
155+
delete_job_file_task = delete_job_file()
156+
119157
(
120158
# TEST SETUP
121-
create_bucket
122-
>> [upload_file, create_cluster]
159+
[[create_job_file_task, create_bucket] >> upload_file, create_cluster]
123160
# TEST BODY
124161
>> pyspark_task
125162
# TEST TEARDOWN
126-
>> [delete_cluster, delete_bucket]
163+
>> [delete_cluster, delete_bucket, delete_job_file_task]
127164
)
128165

129166
from tests.system.utils.watcher import watcher

0 commit comments

Comments
 (0)