|
22 | 22 |
|
23 | 23 | import os |
24 | 24 | from datetime import datetime |
25 | | -from pathlib import Path |
26 | 25 |
|
27 | 26 | from airflow import models |
| 27 | +from airflow.decorators import task |
28 | 28 | from airflow.providers.google.cloud.operators.dataproc import ( |
29 | 29 | DataprocCreateClusterOperator, |
30 | 30 | DataprocDeleteClusterOperator, |
31 | 31 | DataprocSubmitJobOperator, |
32 | 32 | ) |
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 | +) |
34 | 37 | from airflow.providers.google.cloud.transfers.local_to_gcs import LocalFilesystemToGCSOperator |
35 | 38 | from airflow.utils.trigger_rule import TriggerRule |
36 | 39 |
|
|
43 | 46 | REGION = "europe-west1" |
44 | 47 | ZONE = "europe-west1-b" |
45 | 48 |
|
46 | | -PYSPARK_SRC = str(Path(__file__).parent / "resources" / "hello_world.py") |
47 | | -PYSPARK_FILE = "hello_world.py" |
48 | | - |
49 | 49 | # Cluster definition |
50 | | - |
51 | 50 | CLUSTER_CONFIG = { |
52 | 51 | "master_config": { |
53 | 52 | "num_instances": 1, |
|
61 | 60 | }, |
62 | 61 | } |
63 | 62 |
|
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 | +""" |
65 | 85 |
|
66 | 86 | # Jobs definitions |
67 | 87 | # [START how_to_cloud_dataproc_pyspark_config] |
68 | 88 | PYSPARK_JOB = { |
69 | 89 | "reference": {"project_id": PROJECT_ID}, |
70 | 90 | "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}"}, |
72 | 92 | } |
73 | 93 | # [END how_to_cloud_dataproc_pyspark_config] |
74 | 94 |
|
|
78 | 98 | schedule="@once", |
79 | 99 | start_date=datetime(2021, 1, 1), |
80 | 100 | catchup=False, |
81 | | - tags=["example", "dataproc"], |
| 101 | + tags=["example", "dataproc", "pyspark"], |
82 | 102 | ) as dag: |
83 | 103 | create_bucket = GCSCreateBucketOperator( |
84 | 104 | task_id="create_bucket", bucket_name=BUCKET_NAME, project_id=PROJECT_ID |
85 | 105 | ) |
| 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 | + |
86 | 114 | upload_file = LocalFilesystemToGCSOperator( |
87 | 115 | task_id="upload_file", |
88 | | - src=PYSPARK_SRC, |
89 | | - dst=PYSPARK_FILE, |
| 116 | + src=JOB_FILE_LOCAL_PATH, |
| 117 | + dst=JOB_FILE_NAME, |
90 | 118 | bucket=BUCKET_NAME, |
91 | 119 | ) |
92 | 120 |
|
|
116 | 144 | task_id="delete_bucket", bucket_name=BUCKET_NAME, trigger_rule=TriggerRule.ALL_DONE |
117 | 145 | ) |
118 | 146 |
|
| 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 | + |
119 | 157 | ( |
120 | 158 | # TEST SETUP |
121 | | - create_bucket |
122 | | - >> [upload_file, create_cluster] |
| 159 | + [[create_job_file_task, create_bucket] >> upload_file, create_cluster] |
123 | 160 | # TEST BODY |
124 | 161 | >> pyspark_task |
125 | 162 | # TEST TEARDOWN |
126 | | - >> [delete_cluster, delete_bucket] |
| 163 | + >> [delete_cluster, delete_bucket, delete_job_file_task] |
127 | 164 | ) |
128 | 165 |
|
129 | 166 | from tests.system.utils.watcher import watcher |
|
0 commit comments