Skip to content
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

cloudflare_ruleset causing crash #4560

Open
3 tasks done
arunesh90 opened this issue Nov 12, 2024 · 4 comments
Open
3 tasks done

cloudflare_ruleset causing crash #4560

arunesh90 opened this issue Nov 12, 2024 · 4 comments
Labels
kind/bug Categorizes issue or PR as related to a bug. needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one. triage/debug-log-attached Indicates an issue or PR has a complete Terraform debug log. triage/needs-information Indicates an issue needs more information in order to work on it.

Comments

@arunesh90
Copy link

arunesh90 commented Nov 12, 2024

Confirmation

  • This is a bug with an existing resource and is not a feature request or enhancement. Feature requests should be submitted with Cloudflare Support or your account team.
  • I have searched the issue tracker and my issue isn't already found.
  • I have replicated my issue using the latest version of the provider and it is still present.

Terraform and Cloudflare provider version

Terraform v1.9.8
on darwin_arm64
+ provider registry.terraform.io/cloudflare/cloudflare v4.45.0
+ provider registry.terraform.io/hashicorp/aws v5.75.1
+ provider registry.terraform.io/integrations/github v6.3.1

Affected resource(s)

  • cloudflare_ruleset

Terraform configuration files

resource "cloudflare_ruleset" "http_request_cache_settings" {
  count = var.environment == "production" ? 1 : 0

  zone_id = lookup(data.cloudflare_zones._.zones[0], "id")
  name    = "default"
  kind    = "zone"
  phase   = "http_request_cache_settings"

  rules {
    action      = "set_cache_settings"
    description = "caching"
    enabled     = true
    expression  = "(http.request.full_uri eq \"https://example.com/path1\")"
    action_parameters {
      cache = false
    }
  }

  rules {
    action      = "set_cache_settings"
    description = "caching2"
    enabled     = true
    expression  = "(http.host eq \"example.com\" and starts_with(http.request.uri.path, \"/path1\"))"
    action_parameters {
      cache = false
    }
  }

  rules {
    action      = "set_cache_settings"
    description = "caching3"
    enabled     = true
    expression  = "(http.host eq \"example.com\" and http.request.uri.path eq \"/path1\")"
    action_parameters {
      cache = false
    }
  }

  rules {
    action      = "set_cache_settings"
    description = "caching4"
    enabled     = true
    expression  = "(http.host eq \"example.com\" and http.request.uri.path eq \"/path1/path2\") or (http.host eq \"example.com\" and http.request.uri.path eq \"/path1/path2\")"
    action_parameters {
      cache = false
    }
  }

  rules {
    action      = "set_cache_settings"
    description = "Disable cache for tunneled instances used for testing/dev"
    enabled     = true
    expression  = "(http.host in {\"example.com\" \"example.com\"})"
    action_parameters {
      cache = false
      browser_ttl {
        mode = "bypass"
      }
    }
  }

  rules {
    action      = "set_cache_settings"
    description = "API cache"
    enabled     = true
    expression  = "(http.host in {\"example.com\" \"example.com\"} and http.request.uri.path matches \"^/path1/path2/path3\") or (http.host in {\"example.com\" \"example.com\"} and http.request.uri.path in {\"/path1/path2\"})"
    action_parameters {
      edge_ttl {
        mode = "respect_origin"
      }
      browser_ttl {
        mode = "respect_origin"
      }
    }
  }

  rules {
    action      = "set_cache_settings"
    description = "Homepage cache"
    enabled     = true
    expression  = "(http.host in {\"example1.com\" \"example2.com\"} and http.request.uri.path eq \"/\")"
    action_parameters {
      cache = true
    }
  }
}

Link to debug output

https://gist.github.com/arunesh90/63af12b26e8546d5f783fa24442ef7dc

Panic output

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0xf65cb2]

goroutine 142 [running]:
github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/rulesets.toRulesetResourceModel({0x21060d8, 0xc000f68e70}, {0x70?, {0xc00060a680?, 0xc00060a160?}}, {0x20?, {0x0?, 0x0?}}, {{0xc000e85932, 0x20}, ...})
	github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/rulesets/resource.go:644 +0x3e32
github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/rulesets.(*RulesetResource).Read(0xc00103c000, {0x21060d8, 0xc000f68e70}, {{{{0x210e310, 0xc0012cfbc0}, {0x18d5c20, 0xc001b4b9b0}}, {0x2112df0, 0xc00155d540}}, 0xc001376018, ...}, ...)
	github.com/cloudflare/terraform-provider-cloudflare/internal/framework/service/rulesets/resource.go:209 +0x519
github.com/hashicorp/terraform-plugin-framework/internal/fwserver.(*Server).ReadResource(0xc000870000, {0x21060d8, 0xc000f68e70}, 0xc000f68ed0, 0xc000d8f578)
	github.com/hashicorp/[email protected]/internal/fwserver/server_readresource.go:117 +0x84e
github.com/hashicorp/terraform-plugin-framework/internal/proto6server.(*Server).ReadResource(0xc000870000, {0x21060d8?, 0xc000f68d80?}, 0xc0005cc2c0)
	github.com/hashicorp/[email protected]/internal/proto6server/server_readresource.go:55 +0x38e
github.com/hashicorp/terraform-plugin-mux/tf6muxserver.(*muxServer).ReadResource(0xc000ba24d0, {0x21060d8?, 0xc000f68a20?}, 0xc0005cc2c0)
	github.com/hashicorp/[email protected]/tf6muxserver/mux_server_ReadResource.go:35 +0x193
github.com/hashicorp/terraform-plugin-go/tfprotov6/tf6server.(*server).ReadResource(0xc000bdc320, {0x21060d8?, 0xc000f68210?}, 0xc00086a1c0)
	github.com/hashicorp/[email protected]/tfprotov6/tf6server/server.go:784 +0x309
github.com/hashicorp/terraform-plugin-go/tfprotov6/internal/tfplugin6._Provider_ReadResource_Handler({0x1db9ca0, 0xc000bdc320}, {0x21060d8, 0xc000f68210}, 0xc000ccc000, 0x0)
	github.com/hashicorp/[email protected]/tfprotov6/internal/tfplugin6/tfplugin6_grpc.pb.go:509 +0x1a6
google.golang.org/grpc.(*Server).processUnaryRPC(0xc0005e0200, {0x21060d8, 0xc000f68180}, {0x210f580, 0xc0009d2b60}, 0xc001554000, 0xc00085acf0, 0x2f1f248, 0x0)
	google.golang.org/[email protected]/server.go:1394 +0xe49
google.golang.org/grpc.(*Server).handleStream(0xc0005e0200, {0x210f580, 0xc0009d2b60}, 0xc001554000)
	google.golang.org/[email protected]/server.go:1805 +0xe8b
google.golang.org/grpc.(*Server).serveStreams.func2.1()
	google.golang.org/[email protected]/server.go:1029 +0x8b
created by google.golang.org/grpc.(*Server).serveStreams.func2 in goroutine 70
	google.golang.org/[email protected]/server.go:1040 +0x125

Expected output

One of our cache rules got recently manually changed on the dashboard while it's managed by the config above, so the expectation from this new plan would be to sync it back up or at least give some kind of error/warning about it - Instead it appears that something inside the ruleset code of the provider crashed.
The exact rule that got changed is the Homepage cache one from my config.
On the dashboard we simply added another hostname, so it's now:

(http.host in {"example1.com" "example2.com" "example3.com"} and http.request.uri.path eq "/")

versus what's in the config:

(http.host in {"example1.com" "example2.com"} and http.request.uri.path eq "/")

Seems as if the ruleset code had issues handling that manual change and couldn't generate a change for that and proceeded to crash.

Actual output

Provider should've created a change for my ruleset that got manually edited, but instead it crashed.

Steps to reproduce

  1. Create cache rule like the Homepage cache one from my config, via Terraform
  2. Manually edit it in the dashboard
  3. Trigger another Terraform plan
  4. Crash

Additional factoids

No response

References

No response

@arunesh90 arunesh90 added kind/bug Categorizes issue or PR as related to a bug. needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one. labels Nov 12, 2024
Copy link
Contributor

Community Note

Voting for Prioritization

  • Please vote on this issue by adding a 👍 reaction to the original post to help the community and maintainers prioritize this request.
  • Please do not leave "+1" or other comments that do not add relevant new information or questions, they generate extra noise for issue followers and do not help prioritize the request.

Volunteering to Work on This Issue

  • If you are interested in working on this issue, please leave a comment.
  • If this would be your first contribution, please review the contribution guide.

@github-actions github-actions bot added the triage/debug-log-attached Indicates an issue or PR has a complete Terraform debug log. label Nov 12, 2024
Copy link
Contributor

Thank you for opening this issue and sorry to hear you're hitting issues. Unfortunately, the reproduction case provided contains HCL dynamic expressions. Examples of these are:

Maintainers don't accept these as reproduction cases since using these constructs and expressions can hold their own logic bugs which are outside of the provider and not able to be diagnosed.

For maintainers to triage this issue, we recommend providing a minimal reproduction test case that is only contains the impacted resources and can be easily reproduced in an isolated environment. Without providing this, maintainers are limited in what support they can provide.

@github-actions github-actions bot added the triage/needs-information Indicates an issue needs more information in order to work on it. label Nov 12, 2024
@arunesh90
Copy link
Author

Sorry for the delay, but I can confirm this is happening for me without the conditional as well.

@jacobbednarz
Copy link
Member

running this without conditionals is working expected for me.

HCL

```hcl
resource "cloudflare_ruleset" "http_request_cache_settings" {
  zone_id = var.zone_id
  name    = "default"
  kind    = "zone"
  phase   = "http_request_cache_settings"

  rules {
    action      = "set_cache_settings"
    description = "caching"
    enabled     = true
    expression  = "(http.request.full_uri eq \"https://example.com/path1\")"
    action_parameters {
      cache = false
    }
  }

  rules {
    action      = "set_cache_settings"
    description = "caching2"
    enabled     = true
    expression  = "(http.host eq \"example.com\" and starts_with(http.request.uri.path, \"/path1\"))"
    action_parameters {
      cache = false
    }
  }

  rules {
    action      = "set_cache_settings"
    description = "caching3"
    enabled     = true
    expression  = "(http.host eq \"example.com\" and http.request.uri.path eq \"/path1\")"
    action_parameters {
      cache = false
    }
  }

  rules {
    action      = "set_cache_settings"
    description = "caching4"
    enabled     = true
    expression  = "(http.host eq \"example.com\" and http.request.uri.path eq \"/path1/path2\") or (http.host eq \"example.com\" and http.request.uri.path eq \"/path1/path2\")"
    action_parameters {
      cache = false
    }
  }

  rules {
    action      = "set_cache_settings"
    description = "Disable cache for tunneled instances used for testing/dev"
    enabled     = true
    expression  = "(http.host in {\"example.com\" \"example.com\"})"
    action_parameters {
      cache = false
      browser_ttl {
        mode = "bypass"
      }
    }
  }

  rules {
    action      = "set_cache_settings"
    description = "API cache"
    enabled     = true
    expression  = "(http.host in {\"example.com\" \"example.com\"} and http.request.uri.path matches \"^/path1/path2/path3\") or (http.host in {\"example.com\" \"example.com\"} and http.request.uri.path in {\"/path1/path2\"})"
    action_parameters {
      edge_ttl {
        mode = "respect_origin"
      }
      browser_ttl {
        mode = "respect_origin"
      }
    }
  }

  rules {
    action      = "set_cache_settings"
    description = "Homepage cache"
    enabled     = true
    expression  = "(http.host in {\"example1.com\" \"example2.com\"} and http.request.uri.path eq \"/\")"
    action_parameters {
      cache = true
    }
  }
}

Apply + plan

$ terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # cloudflare_ruleset.http_request_cache_settings will be created
  + resource "cloudflare_ruleset" "http_request_cache_settings" {
      + description = (known after apply)
      + id          = (known after apply)
      + kind        = "zone"
      + name        = "default"
      + phase       = "http_request_cache_settings"
      + zone_id     = "0da42c8d2132a9ddaf714f9e7c920711"

      + rules {
          + action       = "set_cache_settings"
          + description  = "caching"
          + enabled      = true
          + expression   = "(http.request.full_uri eq \"https://example.com/path1\")"
          + id           = (known after apply)
          + last_updated = (known after apply)
          + ref          = (known after apply)
          + version      = (known after apply)

          + action_parameters {
              + cache   = false
              + version = (known after apply)
            }
        }
      + rules {
          + action       = "set_cache_settings"
          + description  = "caching2"
          + enabled      = true
          + expression   = "(http.host eq \"example.com\" and starts_with(http.request.uri.path, \"/path1\"))"
          + id           = (known after apply)
          + last_updated = (known after apply)
          + ref          = (known after apply)
          + version      = (known after apply)

          + action_parameters {
              + cache   = false
              + version = (known after apply)
            }
        }
      + rules {
          + action       = "set_cache_settings"
          + description  = "caching3"
          + enabled      = true
          + expression   = "(http.host eq \"example.com\" and http.request.uri.path eq \"/path1\")"
          + id           = (known after apply)
          + last_updated = (known after apply)
          + ref          = (known after apply)
          + version      = (known after apply)

          + action_parameters {
              + cache   = false
              + version = (known after apply)
            }
        }
      + rules {
          + action       = "set_cache_settings"
          + description  = "caching4"
          + enabled      = true
          + expression   = "(http.host eq \"example.com\" and http.request.uri.path eq \"/path1/path2\") or (http.host eq \"example.com\" and http.request.uri.path eq \"/path1/path2\")"
          + id           = (known after apply)
          + last_updated = (known after apply)
          + ref          = (known after apply)
          + version      = (known after apply)

          + action_parameters {
              + cache   = false
              + version = (known after apply)
            }
        }
      + rules {
          + action       = "set_cache_settings"
          + description  = "Disable cache for tunneled instances used for testing/dev"
          + enabled      = true
          + expression   = "(http.host in {\"example.com\" \"example.com\"})"
          + id           = (known after apply)
          + last_updated = (known after apply)
          + ref          = (known after apply)
          + version      = (known after apply)

          + action_parameters {
              + cache   = false
              + version = (known after apply)

              + browser_ttl {
                  + mode = "bypass"
                }
            }
        }
      + rules {
          + action       = "set_cache_settings"
          + description  = "API cache"
          + enabled      = true
          + expression   = "(http.host in {\"example.com\" \"example.com\"} and http.request.uri.path matches \"^/path1/path2/path3\") or (http.host in {\"example.com\" \"example.com\"} and http.request.uri.path in {\"/path1/path2\"})"
          + id           = (known after apply)
          + last_updated = (known after apply)
          + ref          = (known after apply)
          + version      = (known after apply)

          + action_parameters {
              + version = (known after apply)

              + browser_ttl {
                  + mode = "respect_origin"
                }

              + edge_ttl {
                  + mode = "respect_origin"
                }
            }
        }
      + rules {
          + action       = "set_cache_settings"
          + description  = "Homepage cache"
          + enabled      = true
          + expression   = "(http.host in {\"example1.com\" \"example2.com\"} and http.request.uri.path eq \"/\")"
          + id           = (known after apply)
          + last_updated = (known after apply)
          + ref          = (known after apply)
          + version      = (known after apply)

          + action_parameters {
              + cache   = true
              + version = (known after apply)
            }
        }
    }

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

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

cloudflare_ruleset.http_request_cache_settings: Creating...
cloudflare_ruleset.http_request_cache_settings: Creation complete after 2s [id=fa63a12876934da58f23cfe589382ca6]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
~/s/scratch$ terraform apply
cloudflare_ruleset.http_request_cache_settings: Refreshing state... [id=fa63a12876934da58f23cfe589382ca6]

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

you'll either need to find what has gone wrong in your state or track down what differs here for the repro as it looks to isolated to your setup.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/bug Categorizes issue or PR as related to a bug. needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one. triage/debug-log-attached Indicates an issue or PR has a complete Terraform debug log. triage/needs-information Indicates an issue needs more information in order to work on it.
Projects
None yet
Development

No branches or pull requests

2 participants