Skip to content

Commit acb3700

Browse files
authored
Fixed Issue: The field node_type_id cannot be supplied when an instance pool ID is provided (#3549)
* Fixed Issue: The field 'node_type_id' cannot be supplied when an instance pool ID is provided * Integration test * - * - * fix bug * comments * - * -
1 parent 76a2d61 commit acb3700

File tree

3 files changed

+143
-82
lines changed

3 files changed

+143
-82
lines changed

clusters/resource_cluster.go

Lines changed: 102 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ const DbfsDeprecationWarning = "For init scripts use 'volumes', 'workspace' or c
2222
var clusterSchema = resourceClusterSchema()
2323
var clusterSchemaVersion = 3
2424

25+
const (
26+
numWorkerErr = "NumWorkers could be 0 only for SingleNode clusters. See https://docs.databricks.com/clusters/single-node.html for more details"
27+
unsupportedExceptCreateOrEditErr = "unsupported type %T, must be either %scompute.CreateCluster or %scompute.EditCluster. Please report this issue to the GitHub repo"
28+
)
29+
2530
func ResourceCluster() common.Resource {
2631
return common.Resource{
2732
Create: resourceClusterCreate,
@@ -101,54 +106,101 @@ func ZoneDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
101106

102107
// This method is a duplicate of Validate() in clusters/clusters_api.go that uses Go SDK.
103108
// Long term, Validate() in clusters_api.go will be removed once all the resources using clusters are migrated to Go SDK.
104-
func Validate(cluster ClusterSpec) error {
105-
if cluster.NumWorkers > 0 || cluster.Autoscale != nil {
106-
return nil
109+
func Validate(cluster any) error {
110+
var profile, master, resourceClass string
111+
switch c := cluster.(type) {
112+
case compute.CreateCluster:
113+
if c.NumWorkers > 0 || c.Autoscale != nil {
114+
return nil
115+
}
116+
profile = c.SparkConf["spark.databricks.cluster.profile"]
117+
master = c.SparkConf["spark.master"]
118+
resourceClass = c.CustomTags["ResourceClass"]
119+
case compute.EditCluster:
120+
if c.NumWorkers > 0 || c.Autoscale != nil {
121+
return nil
122+
}
123+
profile = c.SparkConf["spark.databricks.cluster.profile"]
124+
master = c.SparkConf["spark.master"]
125+
resourceClass = c.CustomTags["ResourceClass"]
126+
default:
127+
return fmt.Errorf(unsupportedExceptCreateOrEditErr, cluster, "", "")
107128
}
108-
profile := cluster.SparkConf["spark.databricks.cluster.profile"]
109-
master := cluster.SparkConf["spark.master"]
110-
resourceClass := cluster.CustomTags["ResourceClass"]
111129
if profile == "singleNode" && strings.HasPrefix(master, "local") && resourceClass == "SingleNode" {
112130
return nil
113131
}
114-
return fmt.Errorf("NumWorkers could be 0 only for SingleNode clusters. See https://docs.databricks.com/clusters/single-node.html for more details")
132+
return fmt.Errorf(numWorkerErr)
115133
}
116134

117135
// This method is a duplicate of ModifyRequestOnInstancePool() in clusters/clusters_api.go that uses Go SDK.
118136
// Long term, ModifyRequestOnInstancePool() in clusters_api.go will be removed once all the resources using clusters are migrated to Go SDK.
119-
func ModifyRequestOnInstancePool(cluster *ClusterSpec) {
120-
// Instance profile id does not exist or not set
121-
if cluster.InstancePoolId == "" {
122-
// Worker must use an instance pool if driver uses an instance pool,
123-
// therefore empty the computed value for driver instance pool.
124-
cluster.DriverInstancePoolId = ""
125-
return
126-
}
127-
if cluster.AwsAttributes != nil {
128-
// Reset AwsAttributes
129-
awsAttributes := compute.AwsAttributes{
130-
InstanceProfileArn: cluster.AwsAttributes.InstanceProfileArn,
137+
func ModifyRequestOnInstancePool(cluster any) error {
138+
switch c := cluster.(type) {
139+
case *compute.CreateCluster:
140+
// Instance profile id does not exist or not set
141+
if c.InstancePoolId == "" {
142+
// Worker must use an instance pool if driver uses an instance pool,
143+
// therefore empty the computed value for driver instance pool.
144+
c.DriverInstancePoolId = ""
145+
return nil
131146
}
132-
cluster.AwsAttributes = &awsAttributes
133-
}
134-
if cluster.AzureAttributes != nil {
135-
cluster.AzureAttributes = &compute.AzureAttributes{}
136-
}
137-
if cluster.GcpAttributes != nil {
138-
gcpAttributes := compute.GcpAttributes{
139-
GoogleServiceAccount: cluster.GcpAttributes.GoogleServiceAccount,
147+
if c.AwsAttributes != nil {
148+
// Reset AwsAttributes
149+
awsAttributes := compute.AwsAttributes{
150+
InstanceProfileArn: c.AwsAttributes.InstanceProfileArn,
151+
}
152+
c.AwsAttributes = &awsAttributes
153+
}
154+
if c.AzureAttributes != nil {
155+
c.AzureAttributes = &compute.AzureAttributes{}
156+
}
157+
if c.GcpAttributes != nil {
158+
gcpAttributes := compute.GcpAttributes{
159+
GoogleServiceAccount: c.GcpAttributes.GoogleServiceAccount,
160+
}
161+
c.GcpAttributes = &gcpAttributes
162+
}
163+
c.EnableElasticDisk = false
164+
c.NodeTypeId = ""
165+
c.DriverNodeTypeId = ""
166+
return nil
167+
case *compute.EditCluster:
168+
// Instance profile id does not exist or not set
169+
if c.InstancePoolId == "" {
170+
// Worker must use an instance pool if driver uses an instance pool,
171+
// therefore empty the computed value for driver instance pool.
172+
c.DriverInstancePoolId = ""
173+
return nil
174+
}
175+
if c.AwsAttributes != nil {
176+
// Reset AwsAttributes
177+
awsAttributes := compute.AwsAttributes{
178+
InstanceProfileArn: c.AwsAttributes.InstanceProfileArn,
179+
}
180+
c.AwsAttributes = &awsAttributes
181+
}
182+
if c.AzureAttributes != nil {
183+
c.AzureAttributes = &compute.AzureAttributes{}
140184
}
141-
cluster.GcpAttributes = &gcpAttributes
185+
if c.GcpAttributes != nil {
186+
gcpAttributes := compute.GcpAttributes{
187+
GoogleServiceAccount: c.GcpAttributes.GoogleServiceAccount,
188+
}
189+
c.GcpAttributes = &gcpAttributes
190+
}
191+
c.EnableElasticDisk = false
192+
c.NodeTypeId = ""
193+
c.DriverNodeTypeId = ""
194+
return nil
195+
default:
196+
return fmt.Errorf(unsupportedExceptCreateOrEditErr, cluster, "*", "*")
142197
}
143-
cluster.EnableElasticDisk = false
144-
cluster.NodeTypeId = ""
145-
cluster.DriverNodeTypeId = ""
146198
}
147199

148200
// This method is a duplicate of FixInstancePoolChangeIfAny(d *schema.ResourceData) in clusters/clusters_api.go that uses Go SDK.
149201
// Long term, FixInstancePoolChangeIfAny(d *schema.ResourceData) in clusters_api.go will be removed once all the resources using clusters are migrated to Go SDK.
150202
// https://github.com/databricks/terraform-provider-databricks/issues/824
151-
func FixInstancePoolChangeIfAny(d *schema.ResourceData, cluster ClusterSpec) {
203+
func FixInstancePoolChangeIfAny(d *schema.ResourceData, cluster *compute.EditCluster) {
152204
oldInstancePool, newInstancePool := d.GetChange("instance_pool_id")
153205
oldDriverPool, newDriverPool := d.GetChange("driver_instance_pool_id")
154206
if oldInstancePool != newInstancePool &&
@@ -261,14 +313,14 @@ func resourceClusterCreate(ctx context.Context, d *schema.ResourceData, c *commo
261313
return err
262314
}
263315
clusters := w.Clusters
264-
var cluster ClusterSpec
265-
common.DataToStructPointer(d, clusterSchema, &cluster)
266-
if err := Validate(cluster); err != nil {
267-
return err
268-
}
269-
ModifyRequestOnInstancePool(&cluster)
270316
var createClusterRequest compute.CreateCluster
271317
common.DataToStructPointer(d, clusterSchema, &createClusterRequest)
318+
if err := Validate(createClusterRequest); err != nil {
319+
return err
320+
}
321+
if err = ModifyRequestOnInstancePool(&createClusterRequest); err != nil {
322+
return err
323+
}
272324
if createClusterRequest.Autoscale == nil {
273325
createClusterRequest.ForceSendFields = []string{"NumWorkers"}
274326
}
@@ -290,6 +342,8 @@ func resourceClusterCreate(ctx context.Context, d *schema.ResourceData, c *commo
290342
}
291343
}
292344

345+
var cluster ClusterSpec
346+
common.DataToStructPointer(d, clusterSchema, &cluster)
293347
if len(cluster.Libraries) > 0 {
294348
if err = w.Libraries.Install(ctx, compute.InstallLibraries{
295349
ClusterId: d.Id(),
@@ -382,18 +436,21 @@ func resourceClusterUpdate(ctx context.Context, d *schema.ResourceData, c *commo
382436
return err
383437
}
384438
clusters := w.Clusters
385-
var cluster ClusterSpec
439+
var cluster compute.EditCluster
386440
common.DataToStructPointer(d, clusterSchema, &cluster)
387441
clusterId := d.Id()
442+
cluster.ClusterId = clusterId
388443
var clusterInfo *compute.ClusterDetails
389444

390445
if hasClusterConfigChanged(d) {
391446
log.Printf("[DEBUG] Cluster state has changed!")
392447
if err := Validate(cluster); err != nil {
393448
return err
394449
}
395-
ModifyRequestOnInstancePool(&cluster)
396-
FixInstancePoolChangeIfAny(d, cluster)
450+
if err = ModifyRequestOnInstancePool(&cluster); err != nil {
451+
return err
452+
}
453+
FixInstancePoolChangeIfAny(d, &cluster)
397454

398455
// We can only call the resize api if the cluster is in the running state
399456
// and only the cluster size (ie num_workers OR autoscale) is being changed
@@ -453,10 +510,7 @@ func resourceClusterUpdate(ctx context.Context, d *schema.ResourceData, c *commo
453510
Autoscale: cluster.Autoscale,
454511
})
455512
} else {
456-
var editCluster compute.EditCluster
457-
editCluster.ClusterId = clusterId
458-
common.DataToStructPointer(d, clusterSchema, &editCluster)
459-
_, err = clusters.Edit(ctx, editCluster)
513+
_, err = clusters.Edit(ctx, cluster)
460514
}
461515
if err != nil {
462516
return err
@@ -489,7 +543,9 @@ func resourceClusterUpdate(ctx context.Context, d *schema.ResourceData, c *commo
489543
return err
490544
}
491545

492-
libsToInstall, libsToUninstall := libraries.GetLibrariesToInstallAndUninstall(cluster.Libraries, libsClusterStatus)
546+
var clusterLibraries ClusterSpec
547+
common.DataToStructPointer(d, clusterSchema, &clusterLibraries)
548+
libsToInstall, libsToUninstall := libraries.GetLibrariesToInstallAndUninstall(clusterLibraries.Libraries, libsClusterStatus)
493549

494550
clusterInfo, err = clusters.GetByClusterId(ctx, clusterId)
495551
if err != nil {

clusters/resource_cluster_test.go

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1544,57 +1544,54 @@ func TestResourceClusterUpdate_FailNumWorkersZero(t *testing.T) {
15441544
}
15451545

15461546
func TestModifyClusterRequestAws(t *testing.T) {
1547-
c := ClusterSpec{
1548-
ClusterSpec: compute.ClusterSpec{
1549-
InstancePoolId: "a",
1550-
AwsAttributes: &compute.AwsAttributes{
1551-
InstanceProfileArn: "b",
1552-
ZoneId: "c",
1553-
},
1554-
EnableElasticDisk: true,
1555-
NodeTypeId: "d",
1556-
DriverNodeTypeId: "e",
1547+
c := compute.CreateCluster{
1548+
InstancePoolId: "a",
1549+
AwsAttributes: &compute.AwsAttributes{
1550+
InstanceProfileArn: "b",
1551+
ZoneId: "c",
15571552
},
1553+
EnableElasticDisk: true,
1554+
NodeTypeId: "d",
1555+
DriverNodeTypeId: "e",
15581556
}
1559-
ModifyRequestOnInstancePool(&c)
1557+
err := ModifyRequestOnInstancePool(&c)
1558+
assert.NoError(t, err)
15601559
assert.Equal(t, "", c.AwsAttributes.ZoneId)
15611560
assert.Equal(t, "", c.NodeTypeId)
15621561
assert.Equal(t, "", c.DriverNodeTypeId)
15631562
assert.Equal(t, false, c.EnableElasticDisk)
15641563
}
15651564

15661565
func TestModifyClusterRequestAzure(t *testing.T) {
1567-
c := ClusterSpec{
1568-
ClusterSpec: compute.ClusterSpec{
1569-
InstancePoolId: "a",
1570-
AzureAttributes: &compute.AzureAttributes{
1571-
FirstOnDemand: 1,
1572-
},
1573-
EnableElasticDisk: true,
1574-
NodeTypeId: "d",
1575-
DriverNodeTypeId: "e",
1566+
c := compute.CreateCluster{
1567+
InstancePoolId: "a",
1568+
AzureAttributes: &compute.AzureAttributes{
1569+
FirstOnDemand: 1,
15761570
},
1571+
EnableElasticDisk: true,
1572+
NodeTypeId: "d",
1573+
DriverNodeTypeId: "e",
15771574
}
1578-
ModifyRequestOnInstancePool(&c)
1575+
err := ModifyRequestOnInstancePool(&c)
1576+
assert.NoError(t, err)
15791577
assert.Equal(t, &compute.AzureAttributes{}, c.AzureAttributes)
15801578
assert.Equal(t, "", c.NodeTypeId)
15811579
assert.Equal(t, "", c.DriverNodeTypeId)
15821580
assert.Equal(t, false, c.EnableElasticDisk)
15831581
}
15841582

15851583
func TestModifyClusterRequestGcp(t *testing.T) {
1586-
c := ClusterSpec{
1587-
ClusterSpec: compute.ClusterSpec{
1588-
InstancePoolId: "a",
1589-
GcpAttributes: &compute.GcpAttributes{
1590-
UsePreemptibleExecutors: true,
1591-
},
1592-
EnableElasticDisk: true,
1593-
NodeTypeId: "d",
1594-
DriverNodeTypeId: "e",
1584+
c := compute.CreateCluster{
1585+
InstancePoolId: "a",
1586+
GcpAttributes: &compute.GcpAttributes{
1587+
UsePreemptibleExecutors: true,
15951588
},
1589+
EnableElasticDisk: true,
1590+
NodeTypeId: "d",
1591+
DriverNodeTypeId: "e",
15961592
}
1597-
ModifyRequestOnInstancePool(&c)
1593+
err := ModifyRequestOnInstancePool(&c)
1594+
assert.NoError(t, err)
15981595
assert.Equal(t, false, c.GcpAttributes.UsePreemptibleExecutors)
15991596
assert.Equal(t, "", c.NodeTypeId)
16001597
assert.Equal(t, "", c.DriverNodeTypeId)

internal/acceptance/cluster_test.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package acceptance
22

33
import (
4+
"fmt"
45
"testing"
56
)
67

@@ -48,24 +49,31 @@ func TestAccClusterResource_CreateClusterWithLibraries(t *testing.T) {
4849
})
4950
}
5051

51-
func TestAccClusterResource_CreateSingleNodeCluster(t *testing.T) {
52-
workspaceLevel(t, step{
53-
Template: `
52+
func singleNodeClusterTemplate(autoTerminationMinutes string) string {
53+
return fmt.Sprintf(`
5454
data "databricks_spark_version" "latest" {
5555
}
5656
resource "databricks_cluster" "this" {
5757
cluster_name = "singlenode-{var.RANDOM}"
5858
spark_version = data.databricks_spark_version.latest.id
5959
instance_pool_id = "{env.TEST_INSTANCE_POOL_ID}"
6060
num_workers = 0
61-
autotermination_minutes = 10
61+
autotermination_minutes = %s
6262
spark_conf = {
6363
"spark.databricks.cluster.profile" = "singleNode"
6464
"spark.master" = "local[*]"
6565
}
6666
custom_tags = {
6767
"ResourceClass" = "SingleNode"
6868
}
69-
}`,
69+
}
70+
`, autoTerminationMinutes)
71+
}
72+
73+
func TestAccClusterResource_CreateSingleNodeCluster(t *testing.T) {
74+
workspaceLevel(t, step{
75+
Template: singleNodeClusterTemplate("10"),
76+
}, step{
77+
Template: singleNodeClusterTemplate("20"),
7078
})
7179
}

0 commit comments

Comments
 (0)