Skip to content

Commit 7ec5a01

Browse files
pateuszMateusz Poplawski
andauthored
Added support for shared job clusters (#1098)
Co-authored-by: Mateusz Poplawski <[email protected]>
1 parent adf93c4 commit 7ec5a01

File tree

5 files changed

+159
-8
lines changed

5 files changed

+159
-8
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## 0.4.9
44

55
* Prevent creation of `databricks_group` with `users` and `admins` reserved names ([#1089](https://github.com/databrickslabs/terraform-provider-databricks/issues/1089)).
6+
* Shared job cluster functionality added. ([#1082](https://github.com/databrickslabs/terraform-provider-databricks/issues/1082))
67

78
## 0.4.8
89

docs/resources/job.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ It is possible to create [jobs with multiple tasks](https://docs.databricks.com/
5757
resource "databricks_job" "this" {
5858
name = "Job with multiple tasks"
5959
60+
job_cluster {
61+
job_cluster_key = "j"
62+
new_cluster {
63+
num_workers = 2
64+
spark_version = data.databricks_spark_version.latest.id
65+
node_type_id = data.databricks_node_type.smallest.id
66+
}
67+
}
68+
6069
task {
6170
task_key = "a"
6271
@@ -84,6 +93,16 @@ resource "databricks_job" "this" {
8493
main_class_name = "com.acme.data.Main"
8594
}
8695
}
96+
97+
task {
98+
task_key = "c"
99+
100+
job_cluster_key = "j"
101+
102+
notebook_task {
103+
notebook_path = databricks_notebook.this.path
104+
}
105+
}
87106
}
88107
```
89108

@@ -106,6 +125,11 @@ The following arguments are required:
106125
* `email_notifications` - (Optional) (List) An optional set of email addresses notified when runs of this job begin and complete and when this job is deleted. The default behavior is to not send any emails. This field is a block and is documented below.
107126
* `schedule` - (Optional) (List) An optional periodic schedule for this job. The default behavior is that the job runs when triggered by clicking Run Now in the Jobs UI or sending an API request to runNow. This field is a block and is documented below.
108127

128+
### job_cluster Configuration Block
129+
[Shared job cluster](https://docs.databricks.com/jobs.html#use-shared-job-clusters) specification. Allows multiple tasks in the same job run to reuse the cluster.
130+
* `job_cluster_key` - (Required) Identifier that can be referenced in `task` block, so that cluster is shared between tasks
131+
* `new_cluster` - Same set of parameters as for [databricks_cluster](cluster.md) resource.
132+
109133
### schedule Configuration Block
110134

111135
* `quartz_cron_expression` - (Required) A [Cron expression using Quartz syntax](http://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html) that describes the schedule for a job. This field is required.

jobs/acceptance/job_test.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,16 @@ func TestPreviewAccJobTasks(t *testing.T) {
113113
114114
resource "databricks_job" "this" {
115115
name = "{var.RANDOM}"
116+
117+
job_cluster {
118+
job_cluster_key = "j"
119+
new_cluster {
120+
num_workers = 20
121+
spark_version = data.databricks_spark_version.latest.id
122+
node_type_id = data.databricks_node_type.smallest.id
123+
}
124+
}
125+
116126
task {
117127
task_key = "a"
118128
@@ -147,17 +157,13 @@ func TestPreviewAccJobTasks(t *testing.T) {
147157
148158
task {
149159
task_key = "c"
160+
161+
job_cluster_key = "j"
150162
151163
depends_on {
152164
task_key = "b"
153165
}
154166
155-
new_cluster {
156-
num_workers = 20
157-
spark_version = data.databricks_spark_version.latest.id
158-
node_type_id = data.databricks_node_type.smallest.id
159-
}
160-
161167
notebook_task {
162168
notebook_path = databricks_notebook.this.path
163169
}

jobs/resource_job.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ type JobTaskSettings struct {
8181

8282
ExistingClusterID string `json:"existing_cluster_id,omitempty" tf:"group:cluster_type"`
8383
NewCluster *clusters.Cluster `json:"new_cluster,omitempty" tf:"group:cluster_type"`
84+
JobClusterKey string `json:"job_cluster_key,omitempty" tf:"group:cluster_type"`
8485
Libraries []libraries.Library `json:"libraries,omitempty" tf:"slice_set,alias:library"`
8586
NotebookTask *NotebookTask `json:"notebook_task,omitempty" tf:"group:task_type"`
8687
SparkJarTask *SparkJarTask `json:"spark_jar_task,omitempty" tf:"group:task_type"`
@@ -95,6 +96,11 @@ type JobTaskSettings struct {
9596
RetryOnTimeout bool `json:"retry_on_timeout,omitempty" tf:"computed"`
9697
}
9798

99+
type JobCluster struct {
100+
JobClusterKey string `json:"job_cluster_key,omitempty" tf:"group:cluster_type"`
101+
NewCluster *clusters.Cluster `json:"new_cluster,omitempty" tf:"group:cluster_type"`
102+
}
103+
98104
// JobSettings contains the information for configuring a job on databricks
99105
type JobSettings struct {
100106
Name string `json:"name,omitempty" tf:"default:Untitled"`
@@ -116,8 +122,9 @@ type JobSettings struct {
116122
// END Jobs API 2.0
117123

118124
// BEGIN Jobs API 2.1
119-
Tasks []JobTaskSettings `json:"tasks,omitempty" tf:"alias:task"`
120-
Format string `json:"format,omitempty" tf:"computed"`
125+
Tasks []JobTaskSettings `json:"tasks,omitempty" tf:"alias:task"`
126+
Format string `json:"format,omitempty" tf:"computed"`
127+
JobClusters []JobCluster `json:"job_clusters,omitempty" tf:"alias:job_cluster"`
121128
// END Jobs API 2.1
122129

123130
Schedule *CronSchedule `json:"schedule,omitempty"`

jobs/resource_job_test.go

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,119 @@ func TestResourceJobCreate_MultiTask(t *testing.T) {
207207
assert.Equal(t, "789", d.Id())
208208
}
209209

210+
func TestResourceJobCreate_JobClusters(t *testing.T) {
211+
d, err := qa.ResourceFixture{
212+
Fixtures: []qa.HTTPFixture{
213+
{
214+
Method: "POST",
215+
Resource: "/api/2.1/jobs/create",
216+
ExpectedRequest: JobSettings{
217+
Name: "JobClustered",
218+
Tasks: []JobTaskSettings{
219+
{
220+
TaskKey: "a",
221+
JobClusterKey: "j",
222+
},
223+
{
224+
TaskKey: "b",
225+
NewCluster: &clusters.Cluster{
226+
SparkVersion: "a",
227+
NodeTypeID: "b",
228+
NumWorkers: 3,
229+
},
230+
NotebookTask: &NotebookTask{
231+
NotebookPath: "/Stuff",
232+
},
233+
},
234+
},
235+
MaxConcurrentRuns: 1,
236+
JobClusters: []JobCluster{
237+
{
238+
JobClusterKey: "j",
239+
NewCluster: &clusters.Cluster{
240+
SparkVersion: "b",
241+
NodeTypeID: "c",
242+
NumWorkers: 7,
243+
},
244+
},
245+
{
246+
JobClusterKey: "k",
247+
NewCluster: &clusters.Cluster{
248+
SparkVersion: "x",
249+
NodeTypeID: "y",
250+
NumWorkers: 9,
251+
},
252+
},
253+
},
254+
},
255+
Response: Job{
256+
JobID: 17,
257+
},
258+
},
259+
{
260+
Method: "GET",
261+
Resource: "/api/2.1/jobs/get?job_id=17",
262+
Response: Job{
263+
// good enough for mock
264+
Settings: &JobSettings{
265+
Tasks: []JobTaskSettings{
266+
{
267+
TaskKey: "b",
268+
},
269+
{
270+
TaskKey: "a",
271+
},
272+
},
273+
},
274+
},
275+
},
276+
},
277+
Create: true,
278+
Resource: ResourceJob(),
279+
HCL: `
280+
name = "JobClustered"
281+
282+
job_cluster {
283+
job_cluster_key = "j"
284+
new_cluster {
285+
num_workers = 7
286+
spark_version = "b"
287+
node_type_id = "c"
288+
}
289+
}
290+
291+
job_cluster {
292+
job_cluster_key = "k"
293+
new_cluster {
294+
num_workers = 9
295+
spark_version = "x"
296+
node_type_id = "y"
297+
}
298+
}
299+
300+
task {
301+
task_key = "a"
302+
job_cluster_key = "j"
303+
}
304+
305+
task {
306+
task_key = "b"
307+
308+
new_cluster {
309+
spark_version = "a"
310+
node_type_id = "b"
311+
num_workers = 3
312+
}
313+
314+
notebook_task {
315+
notebook_path = "/Stuff"
316+
}
317+
}`,
318+
}.Apply(t)
319+
assert.NoError(t, err, err)
320+
assert.Equal(t, "17", d.Id())
321+
}
322+
210323
func TestResourceJobCreate_AlwaysRunning(t *testing.T) {
211324
d, err := qa.ResourceFixture{
212325
Fixtures: []qa.HTTPFixture{

0 commit comments

Comments
 (0)