Skip to content

Fix for #47: notebook content state func is called at the wrong time #48

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 29, 2020
Merged

Fix for #47: notebook content state func is called at the wrong time #48

merged 2 commits into from
May 29, 2020

Conversation

sdebruyn
Copy link
Contributor

@sdebruyn sdebruyn commented May 8, 2020

The state func in the content argument for the notebook resource was called during the plan phase. Because I was using a templatefile with a dependency, the computed value was not available yet.

The state func got a guid instead of a base64 string so it fails to parse it (probably because the content is not available yet?)

The validation func should correctly verify if it's a valid base64 string and seems to handle the edge cases of when the value is not computed yet.

This fixes #47

Maybe could you let me know why the state func was there in the first place? Thanks!

@stikkireddy
Copy link
Contributor

Hey @sdebruyn the goal of the statefunc is to not bog down the statefile. Its goal was to store a CRC checksum rather than the whole base64 of the content https://www.terraform.io/docs/extend/schemas/schema-behaviors.html#statefunc.

If we remove the statefunc it will bloat the statefile if there alot of notebooks with the base64 string. There will also be a size limit on how big the base64 that terraform state can store. This was a way to, rather than storage the text, it will storage a checksum instead. Let me see if I can recreate the issue using template files instead. I am working on integration tests for notebooks to cover #41 & #42 so before we merge this let me take a quick look at the issue.

@stikkireddy
Copy link
Contributor

I am not able to recreate the behavior that you described from master branch.
https://gist.github.com/stikkireddy/8450e5951088a06eb0b03ff648d04a51

@sdebruyn
Copy link
Contributor Author

@codecov-commenter
Copy link

codecov-commenter commented May 20, 2020

Codecov Report

Merging #48 into master will decrease coverage by 0.00%.
The diff coverage is 0.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #48      +/-   ##
==========================================
- Coverage   48.86%   48.85%   -0.01%     
==========================================
  Files          44       44              
  Lines        5910     5911       +1     
==========================================
  Hits         2888     2888              
- Misses       2971     2972       +1     
  Partials       51       51              
Flag Coverage Δ
#client 89.42% <ø> (ø)
#provider 37.24% <0.00%> (-0.01%) ⬇️
Impacted Files Coverage Δ
databricks/resource_databricks_notebook.go 7.69% <0.00%> (-0.06%) ⬇️

@stikkireddy
Copy link
Contributor

hey @sdebruyn i have some time today to take a look at this sorry for getting back to you rather late on this topic

@stikkireddy
Copy link
Contributor

stikkireddy commented May 22, 2020

@sdebruyn unfortunately when I run this:

resource "databricks_notebook" "spark_setup" {
  content   = base64encode(templatefile("${path.module}/spark_setup.scala", { blob_host = "testhost" }))
  language  = "SCALA"
  path      = "/Shared/spark_setup.scala"
  overwrite = false
  mkdirs    = true
  format    = "SOURCE"
}

I get a proper plan:

------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # databricks_notebook.spark_setup will be created
  + resource "databricks_notebook" "spark_setup" {
      + content     = "2290279572"
      + format      = "SOURCE"
      + id          = (known after apply)
      + language    = "SCALA"
      + mkdirs      = true
      + object_id   = (known after apply)
      + object_type = (known after apply)
      + overwrite   = false
      + path        = "/Shared/spark_setup.scala"
    }

Plan: 1 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

I am also able to apply appropriately as well.

The actual problem is the interpolation, when the statefunc is called during the plan phase for some reason and if there is an error it panics rather than return the "zero" value of the datatype. The easiest fix for this is to make the state function look like the following:

"content": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
				StateFunc: func(i interface{}) string {
					base64String := i.(string)
					base64, err := convertBase64ToCheckSum(base64String)
					if err != nil {
						return ""
					}
					return base64
				},
			},

Please let me know if the above resolves this issue in your fork.

I would love to avoid having to store the base64 string in the statefile if that can be avoided by a crc checksum to determine state differences instead. This makes the state more scalable to larger workspaces and avoids the rpc error when terraform state calls are over 4 MB which notebooks base64 strings can potentially be over (Especially DBC files).

Copy link
Contributor

@stikkireddy stikkireddy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see if my comment is appropriate and sufficiently resolves your issue.

@sdebruyn
Copy link
Contributor Author

Before I make any changes, I want to make sure that we're seeing the same thing.

I just pulled the latest master. I did go clean ./... and make build. The binary is symlinked to my Terraform providers folder.

➜ ls -al ~/.terraform.d/plugins/
total 0
drwxr-xr-x  3 sam  staff   96 May 18 14:25 .
drwxr-xr-x  5 sam  staff  160 May 25 10:55 ..
lrwxr-xr-x  1 sam  staff  103 May 18 14:25 terraform-provider-databricks -> /Users/sam/projects/go/src/github.com/databrickslabs/databricks-terraform/terraform-provider-databricks

Then I did the following on the repro:

  • git clean -dfx
  • terraform init
  • terraform plan

This is the full output of my commands:

repro-terraform-databricks-template on  master took 22s
➜ git clean -dfx
Removing .terraform/
Removing crash.log

repro-terraform-databricks-template on  master
➜ terraform init

Initializing the backend...

Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "random" (hashicorp/random) 2.2.1...
- Downloading plugin for provider "azurerm" (hashicorp/azurerm) 2.11.0...
- Downloading plugin for provider "azuread" (hashicorp/azuread) 0.8.0...

The following providers do not have any version constraints in configuration,
so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.

* provider.random: version = "~> 2.2"

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

repro-terraform-databricks-template on  master took 8s
➜ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

data.azurerm_client_config.current: Refreshing state...

------------------------------------------------------------------------

Error: rpc error: code = Unavailable desc = transport is closing


panic: illegal base64 data at input byte 8
2020-05-25T10:58:23.168+0200 [DEBUG] plugin.terraform-provider-databricks:
2020-05-25T10:58:23.168+0200 [DEBUG] plugin.terraform-provider-databricks: goroutine 39 [running]:
2020-05-25T10:58:23.168+0200 [DEBUG] plugin.terraform-provider-databricks: github.com/databrickslabs/databricks-terraform/databricks.resourceNotebook.func1(0x1a52180, 0xc0005d6d90, 0x7, 0x0)
2020-05-25T10:58:23.168+0200 [DEBUG] plugin.terraform-provider-databricks: 	/Users/sam/projects/go/src/github.com/databrickslabs/databricks-terraform/databricks/resource_databricks_notebook.go:38 +0x90
2020-05-25T10:58:23.168+0200 [DEBUG] plugin.terraform-provider-databricks: github.com/hashicorp/terraform-plugin-sdk/helper/schema.schemaMap.diffString(0xc00049c870, 0x1c0b724, 0x7, 0xc0004d4780, 0xc00048b4e0, 0x1e6d180, 0xc000368770, 0xc0005c9500, 0x0, 0x0)
2020-05-25T10:58:23.168+0200 [DEBUG] plugin.terraform-provider-databricks: 	/Users/sam/projects/go/src/github.com/databrickslabs/databricks-terraform/vendor/github.com/hashicorp/terraform-plugin-sdk/helper/schema/schema.go:1348 +0x69b
2020-05-25T10:58:23.168+0200 [DEBUG] plugin.terraform-provider-databricks: github.com/hashicorp/terraform-plugin-sdk/helper/schema.schemaMap.diff(0xc00049c870, 0x1c0b724, 0x7, 0xc0004d4780, 0xc00029fe20, 0x1e6d180, 0xc000368770, 0xc0005c9600, 0x0, 0x0)
2020-05-25T10:58:23.169+0200 [DEBUG] plugin.terraform-provider-databricks: 	/Users/sam/projects/go/src/github.com/databrickslabs/databricks-terraform/vendor/github.com/hashicorp/terraform-plugin-sdk/helper/schema/schema.go:952 +0x4d5
2020-05-25T10:58:23.169+0200 [DEBUG] plugin.terraform-provider-databricks: github.com/hashicorp/terraform-plugin-sdk/helper/schema.schemaMap.Diff(0xc00049c870, 0xc0005bccd0, 0xc0005cd950, 0x0, 0x1bccc80, 0xc00049a8a0, 0x1e67f00, 0x1a52180, 0xc0005d67b0, 0x0)
2020-05-25T10:58:23.169+0200 [DEBUG] plugin.terraform-provider-databricks: 	/Users/sam/projects/go/src/github.com/databrickslabs/databricks-terraform/vendor/github.com/hashicorp/terraform-plugin-sdk/helper/schema/schema.go:506 +0x215
2020-05-25T10:58:23.169+0200 [DEBUG] plugin.terraform-provider-databricks: github.com/hashicorp/terraform-plugin-sdk/helper/schema.(*Resource).simpleDiff(0xc0004c0a20, 0xc0005bccd0, 0xc0005cd950, 0x1bccc80, 0xc00049a8a0, 0xc0005cd901, 0xc0005c9888, 0x100f8dd)
2020-05-25T10:58:23.169+0200 [DEBUG] plugin.terraform-provider-databricks: 	/Users/sam/projects/go/src/github.com/databrickslabs/databricks-terraform/vendor/github.com/hashicorp/terraform-plugin-sdk/helper/schema/resource.go:356 +0x85
2020-05-25T10:58:23.169+0200 [DEBUG] plugin.terraform-provider-databricks: github.com/hashicorp/terraform-plugin-sdk/helper/schema.(*Provider).SimpleDiff(0xc0004f4000, 0xc0005c9a70, 0xc0005bccd0, 0xc0005cd950, 0xc0005cd1a0, 0xc0005cd950, 0x0)
2020-05-25T10:58:23.169+0200 [DEBUG] plugin.terraform-provider-databricks: 	/Users/sam/projects/go/src/github.com/databrickslabs/databricks-terraform/vendor/github.com/hashicorp/terraform-plugin-sdk/helper/schema/provider.go:321 +0x99
2020-05-25T10:58:23.169+0200 [DEBUG] plugin.terraform-provider-databricks: github.com/hashicorp/terraform-plugin-sdk/internal/helper/plugin.(*GRPCProviderServer).PlanResourceChange(0xc0004a2028, 0x1e672e0, 0xc0005cd140, 0xc000368690, 0xc0004a2028, 0xc0005cd140, 0xc0005bab78)
2020-05-25T10:58:23.169+0200 [DEBUG] plugin.terraform-provider-databricks: 	/Users/sam/projects/go/src/github.com/databrickslabs/databricks-terraform/vendor/github.com/hashicorp/terraform-plugin-sdk/internal/helper/plugin/grpc_provider.go:633 +0x79c
2020-05-25T10:58:23.169+0200 [DEBUG] plugin.terraform-provider-databricks: github.com/hashicorp/terraform-plugin-sdk/internal/tfplugin5._Provider_PlanResourceChange_Handler(0x1bcd960, 0xc0004a2028, 0x1e672e0, 0xc0005cd140, 0xc00049ab40, 0x0, 0x1e672e0, 0xc0005cd140, 0xc0005c2480, 0x110)
2020-05-25T10:58:23.169+0200 [DEBUG] plugin.terraform-provider-databricks: 	/Users/sam/projects/go/src/github.com/databrickslabs/databricks-terraform/vendor/github.com/hashicorp/terraform-plugin-sdk/internal/tfplugin5/tfplugin5.pb.go:3287 +0x217
2020-05-25T10:58:23.169+0200 [DEBUG] plugin.terraform-provider-databricks: google.golang.org/grpc.(*Server).processUnaryRPC(0xc00047f380, 0x1e71620, 0xc000782780, 0xc0000ba400, 0xc0001107e0, 0x25868e8, 0x0, 0x0, 0x0)
2020-05-25T10:58:23.169+0200 [DEBUG] plugin.terraform-provider-databricks: 	/Users/sam/projects/go/src/github.com/databrickslabs/databricks-terraform/vendor/google.golang.org/grpc/server.go:1024 +0x501
2020-05-25T10:58:23.169+0200 [DEBUG] plugin.terraform-provider-databricks: google.golang.org/grpc.(*Server).handleStream(0xc00047f380, 0x1e71620, 0xc000782780, 0xc0000ba400, 0x0)
2020-05-25T10:58:23.169+0200 [DEBUG] plugin.terraform-provider-databricks: 	/Users/sam/projects/go/src/github.com/databrickslabs/databricks-terraform/vendor/google.golang.org/grpc/server.go:1313 +0xd3d
2020-05-25T10:58:23.169+0200 [DEBUG] plugin.terraform-provider-databricks: google.golang.org/grpc.(*Server).serveStreams.func1.1(0xc00003c5b0, 0xc00047f380, 0x1e71620, 0xc000782780, 0xc0000ba400)
2020-05-25T10:58:23.169+0200 [DEBUG] plugin.terraform-provider-databricks: 	/Users/sam/projects/go/src/github.com/databrickslabs/databricks-terraform/vendor/google.golang.org/grpc/server.go:722 +0xa1
2020-05-25T10:58:23.169+0200 [DEBUG] plugin.terraform-provider-databricks: created by google.golang.org/grpc.(*Server).serveStreams.func1
2020-05-25T10:58:23.169+0200 [DEBUG] plugin.terraform-provider-databricks: 	/Users/sam/projects/go/src/github.com/databrickslabs/databricks-terraform/vendor/google.golang.org/grpc/server.go:720 +0xa1
2020/05/25 10:58:23 [ERROR] <root>: eval: *terraform.EvalDiff, err: rpc error: code = Unavailable desc = transport is closing
2020/05/25 10:58:23 [ERROR] <root>: eval: *terraform.EvalSequence, err: rpc error: code = Unavailable desc = transport is closing
2020/05/25 10:58:23 [TRACE] [walkPlan] Exiting eval tree: databricks_notebook.spark_setup
2020/05/25 10:58:23 [TRACE] vertex "databricks_notebook.spark_setup": visit complete
2020/05/25 10:58:23 [TRACE] vertex "databricks_notebook.spark_setup": dynamic subgraph encountered errors
2020/05/25 10:58:23 [TRACE] vertex "databricks_notebook.spark_setup": visit complete
2020/05/25 10:58:23 [TRACE] dag/walk: upstream of "meta.count-boundary (EachMode fixup)" errored, so skipping
2020/05/25 10:58:23 [TRACE] dag/walk: upstream of "provider.databricks (close)" errored, so skipping
2020/05/25 10:58:23 [TRACE] dag/walk: upstream of "root" errored, so skipping
2020/05/25 10:58:23 [INFO] backend/local: plan operation completed
2020/05/25 10:58:23 [TRACE] statemgr.Filesystem: removing lock metadata file .terraform.tfstate.lock.info
2020-05-25T10:58:23.170+0200 [DEBUG] plugin: plugin process exited: path=/Users/sam/.terraform.d/plugins/terraform-provider-databricks pid=18728 error="exit status 2"
2020/05/25 10:58:23 [TRACE] statemgr.Filesystem: unlocking terraform.tfstate using fcntl flock
2020-05-25T10:58:23.170+0200 [DEBUG] plugin: plugin exited



!!!!!!!!!!!!!!!!!!!!!!!!!!! TERRAFORM CRASH !!!!!!!!!!!!!!!!!!!!!!!!!!!!

Terraform crashed! This is always indicative of a bug within Terraform.
A crash log has been placed at "crash.log" relative to your current
working directory. It would be immensely helpful if you could please
report the crash with Terraform[1] so that we can fix this.

When reporting bugs, please include your terraform version. That
information is available on the first line of crash.log. You can also
get it by running 'terraform --version' on the command line.

SECURITY WARNING: the "crash.log" file that was created may contain
sensitive information that must be redacted before it is safe to share
on the issue tracker.

[1]: https://github.com/hashicorp/terraform/issues

!!!!!!!!!!!!!!!!!!!!!!!!!!! TERRAFORM CRASH !!!!!!!!!!!!!!!!!!!!!!!!!!!!

Before we proceed, we should make sure that you can repro the crash 😯

@sdebruyn sdebruyn requested a review from stikkireddy May 25, 2020 12:28
@stikkireddy
Copy link
Contributor

Before I make any changes, I want to make sure that we're seeing the same thing.

I communicated very poorly in my last comment. I was able to recreate the issue as well.

As stated in my previous content it only works without the panic if the content is not interpolated such as:

content   = base64encode(templatefile("${path.module}/spark_setup.scala", { blob_host = "testhost" }))

In your scenario you are interpolating it so the following scenario throws an error on my end as well:

resource "random_password" "aadapp_secret" {
  length = 32
}

resource "databricks_notebook" "spark_setup" {
  content   = base64encode(templatefile("${path.module}/spark_setup.scala", { blob_host = random_password.aadapp_secret.result }))
  language  = "SCALA"
  path      = "/Shared/spark_setup.scala"
  overwrite = false
  mkdirs    = true
  format    = "SOURCE"
}

Screen Shot 2020-05-29 at 1 17 26 AM

The error is due to the panic and only works when interpolated fields are entered into the content which are not yet evaluated/computed. The best way to fix it without side effects seem to be just to return a empty string for the state function.

Please let me know if this adds some clarity to my previous statement.

Copy link
Contributor

@stikkireddy stikkireddy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey this looks good to me @sdebruyn please just read over my comment and let me know if its good for you and I will merge this in. And thank you very much again for the contribution!

@sdebruyn
Copy link
Contributor Author

Hi @stikkireddy thank you for your clarification! LGTM :)

@stikkireddy stikkireddy merged commit 9753cdd into databricks:master May 29, 2020
@nfx nfx added the azure Occurring on Azure cloud label Feb 23, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
azure Occurring on Azure cloud
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[ISSUE] Terraform crash log during plan
5 participants