From c7d022ff92755b48059451e002272e42fd8fb74c Mon Sep 17 00:00:00 2001 From: Integralist Date: Wed, 17 Apr 2024 13:36:01 +0100 Subject: [PATCH] feat: vcl_snippets --- fastly/data_source_vcl_snippets.go | 121 ++++++++++++++++++++++++ fastly/data_source_vcl_snippets_test.go | 101 ++++++++++++++++++++ fastly/provider.go | 1 + 3 files changed, 223 insertions(+) create mode 100644 fastly/data_source_vcl_snippets.go create mode 100644 fastly/data_source_vcl_snippets_test.go diff --git a/fastly/data_source_vcl_snippets.go b/fastly/data_source_vcl_snippets.go new file mode 100644 index 000000000..afd4b3eda --- /dev/null +++ b/fastly/data_source_vcl_snippets.go @@ -0,0 +1,121 @@ +package fastly + +import ( + "context" + "encoding/json" + "log" + "strconv" + + gofastly "github.com/fastly/go-fastly/v9/fastly" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/fastly/terraform-provider-fastly/fastly/hashcode" +) + +func dataSourceFastlyVCLSnippets() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceFastlyVCLSnippetsRead, + Schema: map[string]*schema.Schema{ + "service_id": { + Type: schema.TypeString, + Required: true, + Description: "Alphanumeric string identifying the service.", + }, + "service_version": { + Type: schema.TypeInt, + Required: true, + Description: "Integer identifying a service version.", + }, + "vcl_snippets": { + Type: schema.TypeSet, + Computed: true, + Description: "List of all VCL snippets for the version of the service.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "content": { + Type: schema.TypeString, + Computed: true, + Description: "The VCL code that specifies exactly what the snippet does.", + }, + "id": { + Type: schema.TypeString, + Computed: true, + Description: "Alphanumeric string identifying a VCL Snippet.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name for the snippet. ", + }, + "priority": { + Type: schema.TypeInt, + Computed: true, + Description: "Priority determines execution order. Lower numbers execute first.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "The location in generated VCL where the snippet should be placed.", + }, + }, + }, + }, + }, + } +} + +func dataSourceFastlyVCLSnippetsRead(_ context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + conn := meta.(*APIClient).conn + + log.Printf("[DEBUG] Reading VCL snippets") + + remoteState, err := conn.ListSnippets(&gofastly.ListSnippetsInput{ + ServiceID: d.Get("service_id").(string), + ServiceVersion: d.Get("service_version").(int), + }) + if err != nil { + return diag.Errorf("error fetching VCL snippets: %s", err) + } + + hashBase, _ := json.Marshal(remoteState) + hashString := strconv.Itoa(hashcode.String(string(hashBase))) + d.SetId(hashString) + + if err := d.Set("vcl_snippets", flattenDataSourceVCLSnippets(remoteState)); err != nil { + return diag.Errorf("error setting vcl_snippets: %s", err) + } + + return nil +} + +// flattenDataSourceVCLSnippets models data into format suitable for saving to +// Terraform state. +func flattenDataSourceVCLSnippets(remoteState []*gofastly.Snippet) []map[string]any { + result := make([]map[string]any, len(remoteState)) + if len(remoteState) == 0 { + return result + } + + for i, resource := range remoteState { + result[i] = map[string]any{} + + if resource.Content != nil { + result[i]["content"] = *resource.Content + } + if resource.SnippetID != nil { + result[i]["id"] = *resource.SnippetID + } + if resource.Name != nil { + result[i]["name"] = *resource.Name + } + if resource.Priority != nil { + result[i]["priority"] = *resource.Priority + } + if resource.Type != nil { + result[i]["type"] = *resource.Type + } + } + + return result +} diff --git a/fastly/data_source_vcl_snippets_test.go b/fastly/data_source_vcl_snippets_test.go new file mode 100644 index 000000000..4569607c7 --- /dev/null +++ b/fastly/data_source_vcl_snippets_test.go @@ -0,0 +1,101 @@ +package fastly + +import ( + "fmt" + "strconv" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccFastlyDataSourceVCLSnippets_Config(t *testing.T) { + h := generateHex() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccFastlyDataSourceVCLSnippetsConfig(h), + Check: resource.ComposeTestCheckFunc( + func(s *terraform.State) error { + r := s.RootModule().Resources["data.fastly_vcl_snippets.example"] + a := r.Primary.Attributes + + snippets, err := strconv.Atoi(a["vcl_snippets.#"]) + if err != nil { + return err + } + + if snippets != 3 { + return fmt.Errorf("expected three snippets to be returned (as per the config)") + } + + // NOTE: API doesn't guarantee order. + for i := 0; i < 3; i++ { + var found bool + for _, d := range generateNames(h, 3) { + if a[fmt.Sprintf("vcl_snippets.%d.name", i)] == d { + found = true + break + } + } + if !found { + want := fmt.Sprintf("tf_%s_%d", h, i+1) + return fmt.Errorf("expected: %s", want) + } + } + + return nil + }, + ), + }, + }, + }) +} + +func testAccFastlyDataSourceVCLSnippetsConfig(h string) string { + tf := ` +resource "fastly_service_vcl" "example" { + name = "tf_example_service_for_vcl_snippets_data_source" + + domain { + name = "%s.com" + } + + snippet { + name = "tf_%s_1" + content = "# EXAMPLE 1" + type = "init" + priority = 1 + } + + snippet { + name = "tf_%s_2" + content = "# EXAMPLE 2" + type = "init" + priority = 2 + } + + snippet { + name = "tf_%s_3" + content = "# EXAMPLE 3" + type = "init" + priority = 3 + } + + force_destroy = true +} + +data "fastly_vcl_snippets" "example" { + depends_on = [fastly_service_vcl.example] + service_id = fastly_service_vcl.example.id + service_version = fastly_service_vcl.example.active_version +} +` + + return fmt.Sprintf(tf, h, h, h, h) +} diff --git a/fastly/provider.go b/fastly/provider.go index 35087e8da..a0b3d00f6 100644 --- a/fastly/provider.go +++ b/fastly/provider.go @@ -65,6 +65,7 @@ func Provider() *schema.Provider { "fastly_tls_private_key_ids": dataSourceFastlyTLSPrivateKeyIDs(), "fastly_tls_subscription": dataSourceFastlyTLSSubscription(), "fastly_tls_subscription_ids": dataSourceFastlyTLSSubscriptionIDs(), + "fastly_vcl_snippets": dataSourceFastlyVCLSnippets(), "fastly_waf_rules": dataSourceFastlyWAFRules(), }, ResourcesMap: map[string]*schema.Resource{