From ad429669183a7c943cb10ef7c8164a3697f1ab86 Mon Sep 17 00:00:00 2001 From: Daniel Malon Date: Fri, 8 Jan 2021 09:28:01 +0000 Subject: [PATCH] Add Kinesis logging support (#351) * Upgrade go-fastly to v2.1.0 * Add Kinesis logging * Add Kinesis logging documentation * Update fastly/resource_fastly_service_compute.go Co-authored-by: Mark McDonnell * Apply suggestions from code review Co-authored-by: Mark McDonnell Co-authored-by: Mark McDonnell --- ...block_fastly_service_v1_logging_kinesis.go | 240 +++++++++++++ ..._fastly_service_v1_logging_kinesis_test.go | 317 ++++++++++++++++++ fastly/resource_fastly_service_compute.go | 1 + fastly/resource_fastly_service_v1.go | 1 + go.mod | 2 +- go.sum | 4 +- .../fastly/go-fastly/v2/fastly/blobstorage.go | 3 + .../fastly/go-fastly/v2/fastly/client.go | 2 +- .../v2/fastly/custom_tls_activation.go | 205 +++++++++++ .../v2/fastly/custom_tls_certificate.go | 205 +++++++++++ .../v2/fastly/custom_tls_configuration.go | 163 +++++++++ .../fastly/go-fastly/v2/fastly/errors.go | 12 + .../fastly/go-fastly/v2/fastly/ftp.go | 3 + .../fastly/go-fastly/v2/fastly/gcs.go | 3 + .../fastly/go-fastly/v2/fastly/kinesis.go | 242 +++++++++++++ .../fastly/go-fastly/v2/fastly/openstack.go | 3 + .../fastly/go-fastly/v2/fastly/s3.go | 3 + .../fastly/go-fastly/v2/fastly/sftp.go | 3 + .../fastly/go-fastly/v2/fastly/splunk.go | 12 + vendor/modules.txt | 2 +- website/docs/r/service_compute.html.markdown | 15 +- website/docs/r/service_v1.html.markdown | 17 +- .../r/arguments/logging_kinesis.markdown.tmpl | 17 + .../docs/r/service_compute.html.markdown.tmpl | 2 + .../docs/r/service_v1.html.markdown.tmpl | 2 + 25 files changed, 1472 insertions(+), 7 deletions(-) create mode 100644 fastly/block_fastly_service_v1_logging_kinesis.go create mode 100644 fastly/block_fastly_service_v1_logging_kinesis_test.go create mode 100644 vendor/github.com/fastly/go-fastly/v2/fastly/custom_tls_activation.go create mode 100644 vendor/github.com/fastly/go-fastly/v2/fastly/custom_tls_certificate.go create mode 100644 vendor/github.com/fastly/go-fastly/v2/fastly/custom_tls_configuration.go create mode 100644 vendor/github.com/fastly/go-fastly/v2/fastly/kinesis.go create mode 100644 website_src/docs/r/arguments/logging_kinesis.markdown.tmpl diff --git a/fastly/block_fastly_service_v1_logging_kinesis.go b/fastly/block_fastly_service_v1_logging_kinesis.go new file mode 100644 index 000000000..f01badc10 --- /dev/null +++ b/fastly/block_fastly_service_v1_logging_kinesis.go @@ -0,0 +1,240 @@ +package fastly + +import ( + "fmt" + "log" + + gofastly "github.com/fastly/go-fastly/v2/fastly" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +type KinesisServiceAttributeHandler struct { + *DefaultServiceAttributeHandler +} + +func NewServiceLoggingKinesis(sa ServiceMetadata) ServiceAttributeDefinition { + return &KinesisServiceAttributeHandler{ + &DefaultServiceAttributeHandler{ + key: "logging_kinesis", + serviceMetadata: sa, + }, + } +} + +func (h *KinesisServiceAttributeHandler) Process(d *schema.ResourceData, latestVersion int, conn *gofastly.Client) error { + serviceID := d.Id() + ol, nl := d.GetChange(h.GetKey()) + + if ol == nil { + ol = new(schema.Set) + } + if nl == nil { + nl = new(schema.Set) + } + + ols := ol.(*schema.Set) + nls := nl.(*schema.Set) + + removeKinesisLogging := ols.Difference(nls).List() + addKinesisLogging := nls.Difference(ols).List() + + // DELETE old Kinesis logging endpoints. + for _, oRaw := range removeKinesisLogging { + of := oRaw.(map[string]interface{}) + opts := h.buildDelete(of, serviceID, latestVersion) + + log.Printf("[DEBUG] Fastly Kinesis logging endpoint removal opts: %#v", opts) + + if err := deleteKinesis(conn, opts); err != nil { + return err + } + } + + // POST new/updated Kinesis logging endpoints. + for _, nRaw := range addKinesisLogging { + lf := nRaw.(map[string]interface{}) + opts := h.buildCreate(lf, serviceID, latestVersion) + + log.Printf("[DEBUG] Fastly Kinesis logging addition opts: %#v", opts) + + if err := createKinesis(conn, opts); err != nil { + return err + } + } + + return nil +} + +func (h *KinesisServiceAttributeHandler) Read(d *schema.ResourceData, s *gofastly.ServiceDetail, conn *gofastly.Client) error { + // Refresh Kinesis. + log.Printf("[DEBUG] Refreshing Kinesis logging endpoints for (%s)", d.Id()) + kinesisList, err := conn.ListKineses(&gofastly.ListKinesesInput{ + ServiceID: d.Id(), + ServiceVersion: s.ActiveVersion.Number, + }) + + if err != nil { + return fmt.Errorf("[ERR] Error looking up Kinesis logging endpoints for (%s), version (%v): %s", d.Id(), s.ActiveVersion.Number, err) + } + + ell := flattenKinesis(kinesisList) + + if err := d.Set(h.GetKey(), ell); err != nil { + log.Printf("[WARN] Error setting Kinesis logging endpoints for (%s): %s", d.Id(), err) + } + + return nil +} + +func createKinesis(conn *gofastly.Client, i *gofastly.CreateKinesisInput) error { + _, err := conn.CreateKinesis(i) + return err +} + +func deleteKinesis(conn *gofastly.Client, i *gofastly.DeleteKinesisInput) error { + err := conn.DeleteKinesis(i) + + errRes, ok := err.(*gofastly.HTTPError) + if !ok { + return err + } + + // 404 response codes don't result in an error propagating because a 404 could + // indicate that a resource was deleted elsewhere. + if !errRes.IsNotFound() { + return err + } + + return nil +} + +func flattenKinesis(kinesisList []*gofastly.Kinesis) []map[string]interface{} { + var lsl []map[string]interface{} + for _, ll := range kinesisList { + // Convert Kinesis logging to a map for saving to state. + nll := map[string]interface{}{ + "name": ll.Name, + "topic": ll.StreamName, + "region": ll.Region, + "access_key": ll.AccessKey, + "secret_key": ll.SecretKey, + "format": ll.Format, + "format_version": ll.FormatVersion, + "placement": ll.Placement, + "response_condition": ll.ResponseCondition, + } + + // Prune any empty values that come from the default string value in structs. + for k, v := range nll { + if v == "" { + delete(nll, k) + } + } + + lsl = append(lsl, nll) + } + + return lsl +} + +func (h *KinesisServiceAttributeHandler) buildCreate(kinesisMap interface{}, serviceID string, serviceVersion int) *gofastly.CreateKinesisInput { + df := kinesisMap.(map[string]interface{}) + + var vla = h.getVCLLoggingAttributes(df) + return &gofastly.CreateKinesisInput{ + ServiceID: serviceID, + ServiceVersion: serviceVersion, + Name: df["name"].(string), + StreamName: df["topic"].(string), + Region: df["region"].(string), + AccessKey: df["access_key"].(string), + SecretKey: df["secret_key"].(string), + Format: vla.format, + FormatVersion: uintOrDefault(vla.formatVersion), + Placement: vla.placement, + ResponseCondition: vla.responseCondition, + } +} + +func (h *KinesisServiceAttributeHandler) buildDelete(kinesisMap interface{}, serviceID string, serviceVersion int) *gofastly.DeleteKinesisInput { + df := kinesisMap.(map[string]interface{}) + + return &gofastly.DeleteKinesisInput{ + ServiceID: serviceID, + ServiceVersion: serviceVersion, + Name: df["name"].(string), + } +} + +func (h *KinesisServiceAttributeHandler) Register(s *schema.Resource) error { + var blockAttributes = map[string]*schema.Schema{ + // Required fields + "name": { + Type: schema.TypeString, + Required: true, + Description: "The unique name of the Kinesis logging endpoint.", + }, + + "topic": { + Type: schema.TypeString, + Required: true, + Description: "The Kinesis stream name.", + }, + + "region": { + Type: schema.TypeString, + Optional: true, + Default: "us-east-1", + Description: "The AWS region the stream resides in.", + }, + + "access_key": { + Type: schema.TypeString, + Required: true, + Sensitive: true, + Description: "The AWS access key to be used to write to the stream.", + }, + + "secret_key": { + Type: schema.TypeString, + Required: true, + Sensitive: true, + Description: "The AWS secret access key to authenticate with.", + }, + } + + if h.GetServiceMetadata().serviceType == ServiceTypeVCL { + blockAttributes["format"] = &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Apache style log formatting.", + } + blockAttributes["format_version"] = &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Default: 2, + Description: "The version of the custom logging format used for the configured endpoint. Can be either `1` or `2`. (default: `2`).", + ValidateFunc: validateLoggingFormatVersion(), + } + blockAttributes["placement"] = &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Where in the generated VCL the logging call should be placed. Can be `none` or `waf_debug`.", + ValidateFunc: validateLoggingPlacement(), + } + blockAttributes["response_condition"] = &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The name of an existing condition in the configured endpoint, or leave blank to always execute.", + } + } + + s.Schema[h.GetKey()] = &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: blockAttributes, + }, + } + return nil +} diff --git a/fastly/block_fastly_service_v1_logging_kinesis_test.go b/fastly/block_fastly_service_v1_logging_kinesis_test.go new file mode 100644 index 000000000..c52f1dbca --- /dev/null +++ b/fastly/block_fastly_service_v1_logging_kinesis_test.go @@ -0,0 +1,317 @@ +package fastly + +import ( + "fmt" + "log" + "testing" + + gofastly "github.com/fastly/go-fastly/v2/fastly" + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" +) + +func TestResourceFastlyFlattenKinesis(t *testing.T) { + cases := []struct { + remote []*gofastly.Kinesis + local []map[string]interface{} + }{ + { + remote: []*gofastly.Kinesis{ + { + ServiceVersion: 1, + Name: "kinesis-endpoint", + StreamName: "stream-name", + Region: "us-east-1", + AccessKey: "whywouldyoucheckthis", + SecretKey: "thisisthesecretthatneedstobe40characters", + Format: "%h %l %u %t \"%r\" %>s %b %T", + Placement: "none", + ResponseCondition: "always", + FormatVersion: 2, + }, + }, + local: []map[string]interface{}{ + { + "name": "kinesis-endpoint", + "topic": "stream-name", + "region": "us-east-1", + "access_key": "whywouldyoucheckthis", + "secret_key": "thisisthesecretthatneedstobe40characters", + "format": "%h %l %u %t \"%r\" %>s %b %T", + "placement": "none", + "response_condition": "always", + "format_version": uint(2), + }, + }, + }, + } + + for _, c := range cases { + out := flattenKinesis(c.remote) + if diff := cmp.Diff(out, c.local); diff != "" { + t.Fatalf("Error matching: %s", diff) + } + } +} + +func TestAccFastlyServiceV1_logging_kinesis_basic(t *testing.T) { + var service gofastly.ServiceDetail + name := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) + domain := fmt.Sprintf("fastly-test.%s.com", name) + + log1 := gofastly.Kinesis{ + ServiceVersion: 1, + Name: "kinesis-endpoint", + StreamName: "stream-name", + Region: "us-east-1", + AccessKey: "whywouldyoucheckthis", + SecretKey: "thisisthesecretthatneedstobe40characters", + FormatVersion: 2, + Format: "%h %l %u %t \"%r\" %>s %b", + } + + log1_after_update := gofastly.Kinesis{ + ServiceVersion: 1, + Name: "kinesis-endpoint", + StreamName: "new-stream-name", + Region: "us-east-1", + AccessKey: "whywouldyoucheckthis", + SecretKey: "thisisthesecretthatneedstobe40characters", + FormatVersion: 2, + Format: "%h %l %u %t \"%r\" %>s %b %T", + } + + log2 := gofastly.Kinesis{ + ServiceVersion: 1, + Name: "another-kinesis-endpoint", + StreamName: "another-stream-name", + Region: "us-east-1", + AccessKey: "whywouldyoucheckthis", + SecretKey: "thisisthesecretthatneedstobe40characters", + FormatVersion: 2, + Format: "%h %l %u %t \"%r\" %>s %b", + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckServiceV1Destroy, + Steps: []resource.TestStep{ + { + Config: testAccServiceV1KinesisConfig(name, domain), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceV1Exists("fastly_service_v1.foo", &service), + testAccCheckFastlyServiceV1KinesisAttributes(&service, []*gofastly.Kinesis{&log1}, ServiceTypeVCL), + resource.TestCheckResourceAttr( + "fastly_service_v1.foo", "name", name), + resource.TestCheckResourceAttr( + "fastly_service_v1.foo", "logging_kinesis.#", "1"), + ), + }, + + { + Config: testAccServiceV1KinesisConfig_update(name, domain), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceV1Exists("fastly_service_v1.foo", &service), + testAccCheckFastlyServiceV1KinesisAttributes(&service, []*gofastly.Kinesis{&log1_after_update, &log2}, ServiceTypeVCL), + resource.TestCheckResourceAttr( + "fastly_service_v1.foo", "name", name), + resource.TestCheckResourceAttr( + "fastly_service_v1.foo", "logging_kinesis.#", "2"), + ), + }, + }, + }) +} + +func TestAccFastlyServiceV1_logging_kinesis_basic_compute(t *testing.T) { + var service gofastly.ServiceDetail + name := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) + domain := fmt.Sprintf("fastly-test.%s.com", name) + + log1 := gofastly.Kinesis{ + ServiceVersion: 1, + Name: "kinesis-endpoint", + StreamName: "stream-name", + Region: "us-east-1", + AccessKey: "whywouldyoucheckthis", + SecretKey: "thisisthesecretthatneedstobe40characters", + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckServiceV1Destroy, + Steps: []resource.TestStep{ + { + Config: testAccServiceV1KinesisComputeConfig(name, domain), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceV1Exists("fastly_service_compute.foo", &service), + testAccCheckFastlyServiceV1KinesisAttributes(&service, []*gofastly.Kinesis{&log1}, ServiceTypeCompute), + resource.TestCheckResourceAttr( + "fastly_service_compute.foo", "name", name), + resource.TestCheckResourceAttr( + "fastly_service_compute.foo", "logging_kinesis.#", "1"), + ), + }, + }, + }) +} + +func testAccCheckFastlyServiceV1KinesisAttributes(service *gofastly.ServiceDetail, Kinesis []*gofastly.Kinesis, serviceType string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + conn := testAccProvider.Meta().(*FastlyClient).conn + KinesisList, err := conn.ListKineses(&gofastly.ListKinesesInput{ + ServiceID: service.ID, + ServiceVersion: service.ActiveVersion.Number, + }) + + if err != nil { + return fmt.Errorf("[ERR] Error looking up Kinesis Logging for (%s), version (%d): %s", service.Name, service.ActiveVersion.Number, err) + } + + if len(KinesisList) != len(Kinesis) { + return fmt.Errorf("Kineses List count mismatch, expected (%d), got (%d)", len(Kinesis), len(KinesisList)) + } + + log.Printf("[DEBUG] KinesesList = %#v\n", KinesisList) + + for _, e := range Kinesis { + for _, el := range KinesisList { + if e.Name == el.Name { + // we don't know these things ahead of time, so populate them now + e.ServiceID = service.ID + e.ServiceVersion = service.ActiveVersion.Number + // We don't track these, so clear them out because we also wont know + // these ahead of time + el.CreatedAt = nil + el.UpdatedAt = nil + + // Ignore VCL attributes for Compute and set to whatever is returned from the API. + if serviceType == ServiceTypeCompute { + el.FormatVersion = e.FormatVersion + el.Format = e.Format + el.ResponseCondition = e.ResponseCondition + el.Placement = e.Placement + } + + if diff := cmp.Diff(e, el); diff != "" { + return fmt.Errorf("Bad match Kinesis logging match: %s", diff) + } + } + } + } + + return nil + } +} + +func testAccServiceV1KinesisConfig(name string, domain string) string { + return fmt.Sprintf(` +resource "fastly_service_v1" "foo" { + name = "%s" + + domain { + name = "%s" + comment = "tf-kinesis-logging" + } + + backend { + address = "aws.amazon.com" + name = "amazon docs" + } + + logging_kinesis { + name = "kinesis-endpoint" + topic = "stream-name" + region = "us-east-1" + access_key = "whywouldyoucheckthis" + secret_key = "thisisthesecretthatneedstobe40characters" + format = "%%h %%l %%u %%t \"%%r\" %%>s %%b" + } + + force_destroy = true +} +`, name, domain) +} + +func testAccServiceV1KinesisConfig_update(name, domain string) string { + return fmt.Sprintf(` +resource "fastly_service_v1" "foo" { + name = "%s" + + domain { + name = "%s" + comment = "tf-kinesis-logging" + } + + backend { + address = "aws.amazon.com" + name = "amazon docs" + } + + condition { + name = "response_condition_test" + type = "RESPONSE" + priority = 8 + statement = "resp.status == 418" + } + + logging_kinesis { + name = "kinesis-endpoint" + topic = "new-stream-name" + region = "us-east-1" + access_key = "whywouldyoucheckthis" + secret_key = "thisisthesecretthatneedstobe40characters" + format = "%%h %%l %%u %%t \"%%r\" %%>s %%b %%T" + } + + logging_kinesis { + name = "another-kinesis-endpoint" + topic = "another-stream-name" + region = "us-east-1" + access_key = "whywouldyoucheckthis" + secret_key = "thisisthesecretthatneedstobe40characters" + format = "%%h %%l %%u %%t \"%%r\" %%>s %%b" + } + + force_destroy = true +} +`, name, domain) +} + +func testAccServiceV1KinesisComputeConfig(name string, domain string) string { + return fmt.Sprintf(` +resource "fastly_service_compute" "foo" { + name = "%s" + + domain { + name = "%s" + comment = "tf-kinesis-logging" + } + + backend { + address = "aws.amazon.com" + name = "amazon docs" + } + + logging_kinesis { + name = "kinesis-endpoint" + topic = "stream-name" + region = "us-east-1" + access_key = "whywouldyoucheckthis" + secret_key = "thisisthesecretthatneedstobe40characters" + } + + package { + filename = "test_fixtures/package/valid.tar.gz" + source_code_hash = filesha512("test_fixtures/package/valid.tar.gz") + } + + force_destroy = true +} +`, name, domain) +} diff --git a/fastly/resource_fastly_service_compute.go b/fastly/resource_fastly_service_compute.go index c6f95a410..1d0e25364 100644 --- a/fastly/resource_fastly_service_compute.go +++ b/fastly/resource_fastly_service_compute.go @@ -42,6 +42,7 @@ var computeService = &BaseServiceDefinition{ NewServiceLoggingOpenstack(computeAttributes), NewServiceLoggingDigitalOcean(computeAttributes), NewServiceLoggingCloudfiles(computeAttributes), + NewServiceLoggingKinesis(computeAttributes), NewServicePackage(computeAttributes), }, } diff --git a/fastly/resource_fastly_service_v1.go b/fastly/resource_fastly_service_v1.go index d3767c69a..12b070a9a 100644 --- a/fastly/resource_fastly_service_v1.go +++ b/fastly/resource_fastly_service_v1.go @@ -47,6 +47,7 @@ var vclService = &BaseServiceDefinition{ NewServiceLoggingOpenstack(vclAttributes), NewServiceLoggingDigitalOcean(vclAttributes), NewServiceLoggingCloudfiles(vclAttributes), + NewServiceLoggingKinesis(vclAttributes), NewServiceResponseObject(vclAttributes), NewServiceRequestSetting(vclAttributes), NewServiceVCL(vclAttributes), diff --git a/go.mod b/go.mod index abf12356e..19a79348b 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f // indirect - github.com/fastly/go-fastly/v2 v2.0.0 + github.com/fastly/go-fastly/v2 v2.1.0 github.com/google/go-cmp v0.3.0 github.com/google/jsonapi v0.0.0-20180313013858-2dcc18f43696 // indirect github.com/hashicorp/terraform-plugin-sdk v1.1.0 diff --git a/go.sum b/go.sum index 0f2df0ab8..9f7ed0c24 100644 --- a/go.sum +++ b/go.sum @@ -40,8 +40,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= -github.com/fastly/go-fastly/v2 v2.0.0 h1:dCPOEbTXy8ic5CGj6YibPNvRYG01y15H7kHTlC4d57k= -github.com/fastly/go-fastly/v2 v2.0.0/go.mod h1:+gom+YR+9Q5I4biSk/ZjHQGWXxqpRxC3YDVYQcRpZwQ= +github.com/fastly/go-fastly/v2 v2.1.0 h1:VQWCFiUZyCcknyxyhiQwU0MjLYzeK4g1mLo/US2r/P0= +github.com/fastly/go-fastly/v2 v2.1.0/go.mod h1:+gom+YR+9Q5I4biSk/ZjHQGWXxqpRxC3YDVYQcRpZwQ= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= diff --git a/vendor/github.com/fastly/go-fastly/v2/fastly/blobstorage.go b/vendor/github.com/fastly/go-fastly/v2/fastly/blobstorage.go index de9cc0b18..846a3478e 100644 --- a/vendor/github.com/fastly/go-fastly/v2/fastly/blobstorage.go +++ b/vendor/github.com/fastly/go-fastly/v2/fastly/blobstorage.go @@ -19,6 +19,7 @@ type BlobStorage struct { SASToken string `mapstructure:"sas_token"` Period uint `mapstructure:"period"` TimestampFormat string `mapstructure:"timestamp_format"` + CompressionCodec string `mapstructure:"compression_codec"` GzipLevel uint `mapstructure:"gzip_level"` PublicKey string `mapstructure:"public_key"` Format string `mapstructure:"format"` @@ -89,6 +90,7 @@ type CreateBlobStorageInput struct { SASToken string `form:"sas_token,omitempty"` Period uint `form:"period,omitempty"` TimestampFormat string `form:"timestamp_format,omitempty"` + CompressionCodec string `form:"compression_codec,omitempty"` GzipLevel uint `form:"gzip_level,omitempty"` PublicKey string `form:"public_key,omitempty"` Format string `form:"format,omitempty"` @@ -178,6 +180,7 @@ type UpdateBlobStorageInput struct { SASToken *string `form:"sas_token,omitempty"` Period *uint `form:"period,omitempty"` TimestampFormat *string `form:"timestamp_format,omitempty"` + CompressionCodec *string `form:"compression_codec,omitempty"` GzipLevel *uint `form:"gzip_level,omitempty"` PublicKey *string `form:"public_key,omitempty"` Format *string `form:"format,omitempty"` diff --git a/vendor/github.com/fastly/go-fastly/v2/fastly/client.go b/vendor/github.com/fastly/go-fastly/v2/fastly/client.go index 0e122deb1..48e4e437e 100644 --- a/vendor/github.com/fastly/go-fastly/v2/fastly/client.go +++ b/vendor/github.com/fastly/go-fastly/v2/fastly/client.go @@ -46,7 +46,7 @@ const DefaultRealtimeStatsEndpoint = "https://rt.fastly.com" var ProjectURL = "github.com/fastly/go-fastly" // ProjectVersion is the version of this library. -var ProjectVersion = "2.0.0" +var ProjectVersion = "2.1.0" // UserAgent is the user agent for this particular client. var UserAgent = fmt.Sprintf("FastlyGo/%s (+%s; %s)", diff --git a/vendor/github.com/fastly/go-fastly/v2/fastly/custom_tls_activation.go b/vendor/github.com/fastly/go-fastly/v2/fastly/custom_tls_activation.go new file mode 100644 index 000000000..19b3dad2d --- /dev/null +++ b/vendor/github.com/fastly/go-fastly/v2/fastly/custom_tls_activation.go @@ -0,0 +1,205 @@ +package fastly + +import ( + "fmt" + "reflect" + "strconv" + "time" + + "github.com/google/jsonapi" +) + +// TLSActivation represents a /tls/activations response. +type TLSActivation struct { + ID string `jsonapi:"primary,tls_activation"` + Configuration *TLSConfiguration `jsonapi:"relation,tls_configuration"` // TLSConfiguration type shared with BulkCertificate + Domain *TLSDomain `jsonapi:"relation,tls_domain"` // TLSDomain type shared with BulkCertificate + Certificate *CustomTLSCertificate `jsonapi:"relation,tls_certificate"` + CreatedAt *time.Time `jsonapi:"attr,created_at,iso8601"` +} + +// ListTLSActivationsInput is used as input to the ListTLSActivations function. +type ListTLSActivationsInput struct { + FilterTLSCertificateID string // Limit the returned activations to a specific certificate. + FilterTLSConfigurationID string // Limit the returned activations to a specific TLS configuration. + FilterTLSDomainID string // Limit the returned rules to a specific domain name. + Include string // Include related objects. Optional, comma-separated values. Permitted values: tls_certificate, tls_configuration, and tls_domain. + PageNumber int // The page index for pagination. + PageSize int // The number of activations per page. +} + +// formatFilters converts user input into query parameters for filtering. +func (i *ListTLSActivationsInput) formatFilters() map[string]string { + result := map[string]string{} + pairings := map[string]interface{}{ + "filter[tls_certificate.id]": i.FilterTLSCertificateID, + "filter[tls_configuration.id]": i.FilterTLSConfigurationID, + "filter[tls_domain.id]": i.FilterTLSDomainID, + "include": i.Include, + "page[number]": i.PageNumber, + "page[size]": i.PageSize, + } + + for key, value := range pairings { + switch t := reflect.TypeOf(value).String(); t { + case "string": + if value != "" { + result[key] = value.(string) + } + case "int": + if value != 0 { + result[key] = strconv.Itoa(value.(int)) + } + } + } + + return result +} + +// ListTLSActivations list all activations. +func (c *Client) ListTLSActivations(i *ListTLSActivationsInput) ([]*TLSActivation, error) { + p := "/tls/activations" + filters := &RequestOptions{ + Params: i.formatFilters(), + Headers: map[string]string{ + "Accept": "application/vnd.api+json", // this is required otherwise the filters don't work + }, + } + + r, err := c.Get(p, filters) + if err != nil { + return nil, err + } + + data, err := jsonapi.UnmarshalManyPayload(r.Body, reflect.TypeOf(new(TLSActivation))) + if err != nil { + return nil, err + } + + a := make([]*TLSActivation, len(data)) + for i := range data { + typed, ok := data[i].(*TLSActivation) + if !ok { + return nil, fmt.Errorf("unexpected response type: %T", data[i]) + } + a[i] = typed + } + + return a, nil +} + +// GetTLSActivationInput is used as input to the GetTLSActivation function. +type GetTLSActivationInput struct { + ID string + Include *string // Include related objects. Optional, comma-separated values. Permitted values: tls_certificate, tls_configuration, and tls_domain. +} + +// GetTLSActivation retrieve a single activation. +func (c *Client) GetTLSActivation(i *GetTLSActivationInput) (*TLSActivation, error) { + if i.ID == "" { + return nil, ErrMissingID + } + + p := fmt.Sprintf("/tls/activations/%s", i.ID) + + ro := &RequestOptions{ + Headers: map[string]string{ + "Accept": "application/vnd.api+json", // this is required otherwise the params don't work + }, + } + + if i.Include != nil { + ro.Params = map[string]string{"include": *i.Include} + } + + r, err := c.Get(p, ro) + if err != nil { + return nil, err + } + + var a TLSActivation + if err := jsonapi.UnmarshalPayload(r.Body, &a); err != nil { + return nil, err + } + + return &a, nil +} + +// CreateTLSActivationInput is used as input to the CreateTLSActivation function. +type CreateTLSActivationInput struct { + ID string `jsonapi:"primary,tls_activation"` // ID value does not need to be set. + Certificate *CustomTLSCertificate `jsonapi:"relation,tls_certificate"` // Only ID of CustomTLSCertificate needs to be set. + Configuration *TLSConfiguration `jsonapi:"relation,tls_configuration"` + Domain *TLSDomain `jsonapi:"relation,tls_domain"` +} + +// CreateTLSActivation enable TLS for a domain using a custom certificate. +func (c *Client) CreateTLSActivation(i *CreateTLSActivationInput) (*TLSActivation, error) { + if i.Certificate == nil { + return nil, ErrMissingTLSCertificate + } + if i.Configuration == nil { + return nil, ErrMissingTLSConfiguration + } + if i.Domain == nil { + return nil, ErrMissingTLSDomain + } + + p := "/tls/activations" + + r, err := c.PostJSONAPI(p, i, nil) + if err != nil { + return nil, err + } + + var a TLSActivation + if err := jsonapi.UnmarshalPayload(r.Body, &a); err != nil { + return nil, err + } + + return &a, nil +} + +// UpdateTLSActivationInput is used as input to the UpdateTLSActivation function. +type UpdateTLSActivationInput struct { + ID string `jsonapi:"primary,tls_activation"` + Certificate *CustomTLSCertificate `jsonapi:"relation,tls_certificate"` // Only ID of CustomTLSCertificate needs to be set. +} + +// UpdateTLSActivation updates the certificate used to terminate TLS traffic for the domain associated with this TLS activation. +func (c *Client) UpdateTLSActivation(i *UpdateTLSActivationInput) (*TLSActivation, error) { + if i.ID == "" { + return nil, ErrMissingID + } + if i.Certificate == nil { + return nil, ErrMissingTLSCertificate + } + + path := fmt.Sprintf("/tls/activations/%s", i.ID) + resp, err := c.PatchJSONAPI(path, i, nil) + if err != nil { + return nil, err + } + + var ta TLSActivation + if err := jsonapi.UnmarshalPayload(resp.Body, &ta); err != nil { + return nil, err + } + return &ta, nil +} + +// DeleteTLSActivationInput used for deleting a certificate. +type DeleteTLSActivationInput struct { + ID string +} + +// DeleteTLSActivation destroy a certificate. +func (c *Client) DeleteTLSActivation(i *DeleteTLSActivationInput) error { + if i.ID == "" { + return ErrMissingID + } + + path := fmt.Sprintf("/tls/activations/%s", i.ID) + _, err := c.Delete(path, nil) + return err +} diff --git a/vendor/github.com/fastly/go-fastly/v2/fastly/custom_tls_certificate.go b/vendor/github.com/fastly/go-fastly/v2/fastly/custom_tls_certificate.go new file mode 100644 index 000000000..10d259e88 --- /dev/null +++ b/vendor/github.com/fastly/go-fastly/v2/fastly/custom_tls_certificate.go @@ -0,0 +1,205 @@ +package fastly + +import ( + "fmt" + "reflect" + "strconv" + "time" + + "github.com/google/jsonapi" +) + +// CustomTLSCertificate represents a custom certificate. Uses common TLSDomain type from BulkCertificate. +type CustomTLSCertificate struct { + ID string `jsonapi:"primary,tls_certificate"` + IssuedTo string `jsonapi:"attr,issued_to"` + Issuer string `jsonapi:"attr,issuer"` + Name string `jsonapi:"attr,name"` + NotAfter *time.Time `jsonapi:"attr,not_after,iso8601"` + NotBefore *time.Time `jsonapi:"attr,not_before,iso8601"` + Replace bool `jsonapi:"attr,replace"` + SerialNumber string `jsonapi:"attr,serial_number"` + SignatureAlgorithm string `jsonapi:"attr,signature_algorithm"` + TLSDomains []*TLSDomain `jsonapi:"relation,tls_domains"` + CreatedAt *time.Time `jsonapi:"attr,created_at,iso8601"` + UpdatedAt *time.Time `jsonapi:"attr,updated_at,iso8601"` +} + +// ListCustomTLSCertificatesInput is used as input to the ListCustomTLSCertificatesInput function. +type ListCustomTLSCertificatesInput struct { + FilterNotAfter string // Limit the returned certificates to those that expire prior to the specified date in UTC. Accepts parameters: lte (e.g., filter[not_after][lte]=2020-05-05). + FilterTLSDomainsID string // Limit the returned certificates to those that include the specific domain. + Include string // Include related objects. Optional, comma-separated values. Permitted values: tls_activations. + PageNumber int // The page index for pagination. + PageSize int // The number of keys per page. + Sort string // The order in which to list certificates. Valid values are created_at, not_before, not_after. May precede any value with a - for descending. +} + +// formatFilters converts user input into query parameters for filtering. +func (i *ListCustomTLSCertificatesInput) formatFilters() map[string]string { + result := map[string]string{} + pairings := map[string]interface{}{ + "filter[not_after]": i.FilterNotAfter, + "filter[tls_domains.id]": i.FilterTLSDomainsID, + "include": i.Include, + "page[size]": i.PageSize, + "page[number]": i.PageNumber, + "sort": i.Sort, + } + + for key, value := range pairings { + switch t := reflect.TypeOf(value).String(); t { + case "string": + if value != "" { + result[key] = value.(string) + } + case "int": + if value != 0 { + result[key] = strconv.Itoa(value.(int)) + } + } + } + + return result +} + +// ListCustomTLSCertificates list all certificates. +func (c *Client) ListCustomTLSCertificates(i *ListCustomTLSCertificatesInput) ([]*CustomTLSCertificate, error) { + p := "/tls/certificates" + filters := &RequestOptions{ + Params: i.formatFilters(), + Headers: map[string]string{ + "Accept": "application/vnd.api+json", // this is required otherwise the filters don't work + }, + } + + r, err := c.Get(p, filters) + if err != nil { + return nil, err + } + + data, err := jsonapi.UnmarshalManyPayload(r.Body, reflect.TypeOf(new(CustomTLSCertificate))) + if err != nil { + return nil, err + } + + cc := make([]*CustomTLSCertificate, len(data)) + for i := range data { + typed, ok := data[i].(*CustomTLSCertificate) + if !ok { + return nil, fmt.Errorf("unexpected response type: %T", data[i]) + } + cc[i] = typed + } + + return cc, nil +} + +// GetCustomTLSCertificateInput is used as input to the GetCustomTLSCertificate function. +type GetCustomTLSCertificateInput struct { + ID string +} + +func (c *Client) GetCustomTLSCertificate(i *GetCustomTLSCertificateInput) (*CustomTLSCertificate, error) { + if i.ID == "" { + return nil, ErrMissingID + } + + p := fmt.Sprintf("/tls/certificates/%s", i.ID) + + r, err := c.Get(p, nil) + if err != nil { + return nil, err + } + + var cc CustomTLSCertificate + if err := jsonapi.UnmarshalPayload(r.Body, &cc); err != nil { + return nil, err + } + + return &cc, nil +} + +// CreateCustomTLSCertificateInput is used as input to the CreateCustomTLSCertificate function. +type CreateCustomTLSCertificateInput struct { + ID string `jsonapi:"primary,tls_certificate"` // ID value does not need to be set. + CertBlob string `jsonapi:"attr,cert_blob"` + Name string `jsonapi:"attr,name"` +} + +// CreateCustomTLSCertificate creates a custom TLS certificate. +func (c *Client) CreateCustomTLSCertificate(i *CreateCustomTLSCertificateInput) (*CustomTLSCertificate, error) { + if i.CertBlob == "" { + return nil, ErrMissingCertBlob + } + if i.Name == "" { + return nil, ErrMissingName + } + + p := "/tls/certificates" + + r, err := c.PostJSONAPI(p, i, nil) + if err != nil { + return nil, err + } + + var cc CustomTLSCertificate + if err := jsonapi.UnmarshalPayload(r.Body, &cc); err != nil { + return nil, err + } + + return &cc, nil +} + +// UpdateCustomTLSCertificateInput is used as input to the UpdateCustomTLSCertificate function. +type UpdateCustomTLSCertificateInput struct { + ID string `jsonapi:"primary,tls_certificate"` + CertBlob string `jsonapi:"attr,cert_blob"` + Name string `jsonapi:"attr,name"` +} + +// UpdateCustomTLSCertificate replace a certificate with a newly reissued certificate. +// By using this endpoint, the original certificate will cease to be used for future TLS handshakes. +// Thus, only SAN entries that appear in the replacement certificate will become TLS enabled. +// Any SAN entries that are missing in the replacement certificate will become disabled. +func (c *Client) UpdateCustomTLSCertificate(i *UpdateCustomTLSCertificateInput) (*CustomTLSCertificate, error) { + if i.ID == "" { + return nil, ErrMissingID + } + + if i.CertBlob == "" { + return nil, ErrMissingCertBlob + } + + if i.Name == "" { + return nil, ErrMissingName + } + + path := fmt.Sprintf("/tls/certificates/%s", i.ID) + resp, err := c.PatchJSONAPI(path, i, nil) + if err != nil { + return nil, err + } + + var cc CustomTLSCertificate + if err := jsonapi.UnmarshalPayload(resp.Body, &cc); err != nil { + return nil, err + } + return &cc, nil +} + +// DeleteCustomTLSCertificateInput used for deleting a certificate. +type DeleteCustomTLSCertificateInput struct { + ID string +} + +// DeleteCustomTLSCertificate destroy a certificate. This disables TLS for all domains listed as SAN entries. +func (c *Client) DeleteCustomTLSCertificate(i *DeleteCustomTLSCertificateInput) error { + if i.ID == "" { + return ErrMissingID + } + + path := fmt.Sprintf("/tls/certificates/%s", i.ID) + _, err := c.Delete(path, nil) + return err +} diff --git a/vendor/github.com/fastly/go-fastly/v2/fastly/custom_tls_configuration.go b/vendor/github.com/fastly/go-fastly/v2/fastly/custom_tls_configuration.go new file mode 100644 index 000000000..3e5d54574 --- /dev/null +++ b/vendor/github.com/fastly/go-fastly/v2/fastly/custom_tls_configuration.go @@ -0,0 +1,163 @@ +package fastly + +import ( + "fmt" + "reflect" + "strconv" + "time" + + "github.com/google/jsonapi" +) + +// CustomTLSConfiguration represents a TLS configuration response from the Fastly API. +type CustomTLSConfiguration struct { + ID string `jsonapi:"primary,tls_configuration"` + DNSRecords []*DNSRecord `jsonapi:"relation,dns_records"` + Bulk bool `jsonapi:"attr,bulk"` + Default bool `jsonapi:"attr,default"` + HTTPProtocols []string `jsonapi:"attr,http_protocols"` + Name string `jsonapi:"attr,name"` + TLSProtocols []string `jsonapi:"attr,tls_protocols"` + CreatedAt *time.Time `jsonapi:"attr,created_at,iso8601"` + UpdatedAt *time.Time `jsonapi:"attr,updated_at,iso8601"` +} + +// DNSRecord is a child of CustomTLSConfiguration +type DNSRecord struct { + ID string `jsonapi:"primary,dns_record"` + RecordType string `jsonapi:"attr,record_type"` + Region string `jsonapi:"attr,region"` +} + +// ListCustomTLSConfigurationsInput is used as input to the ListCustomTLSConfigurationsInput function. +type ListCustomTLSConfigurationsInput struct { + FilterBulk bool // Whether or not to only include bulk=true configurations + Include string // Include related objects. Optional, comma-separated values. Permitted values: dns_records. + PageNumber int // The page index for pagination. + PageSize int // The number of keys per page. + +} + +// formatFilters converts user input into query parameters for filtering. +func (i *ListCustomTLSConfigurationsInput) formatFilters() map[string]string { + result := map[string]string{} + pairings := map[string]interface{}{ + "filter[bulk]": i.FilterBulk, + "include": i.Include, + "page[size]": i.PageSize, + "page[number]": i.PageNumber, + } + + for key, value := range pairings { + switch t := reflect.TypeOf(value).String(); t { + case "string": + if value != "" { + result[key] = value.(string) + } + case "int": + if value != 0 { + result[key] = strconv.Itoa(value.(int)) + } + } + } + + return result +} + +// ListCustomTLSConfigurations list all TLS configurations. +func (c *Client) ListCustomTLSConfigurations(i *ListCustomTLSConfigurationsInput) ([]*CustomTLSConfiguration, error) { + p := "/tls/configurations" + ro := &RequestOptions{ + Params: i.formatFilters(), + Headers: map[string]string{ + "Accept": "application/vnd.api+json", // this is required otherwise the filters don't work + }, + } + + r, err := c.Get(p, ro) + if err != nil { + return nil, err + } + + data, err := jsonapi.UnmarshalManyPayload(r.Body, reflect.TypeOf(new(CustomTLSConfiguration))) + if err != nil { + return nil, err + } + + con := make([]*CustomTLSConfiguration, len(data)) + for i := range data { + typed, ok := data[i].(*CustomTLSConfiguration) + if !ok { + return nil, fmt.Errorf("unexpected response type: %T", data[i]) + } + con[i] = typed + } + + return con, nil +} + +// GetCustomTLSConfigurationInput is used as input to the GetCustomTLSConfiguration function. +type GetCustomTLSConfigurationInput struct { + ID string + Include string // Include related objects. Optional, comma-separated values. Permitted values: dns_records. +} + +// GetCustomTLSConfiguration returns a single TLS configuration. +func (c *Client) GetCustomTLSConfiguration(i *GetCustomTLSConfigurationInput) (*CustomTLSConfiguration, error) { + if i.ID == "" { + return nil, ErrMissingID + } + + p := fmt.Sprintf("/tls/configurations/%s", i.ID) + + ro := &RequestOptions{ + Headers: map[string]string{ + "Accept": "application/vnd.api+json", // this is required otherwise the params don't work + }, + } + + if i.Include != "" { + ro.Params = map[string]string{"include": i.Include} + } + + r, err := c.Get(p, ro) + if err != nil { + return nil, err + } + + var con CustomTLSConfiguration + if err := jsonapi.UnmarshalPayload(r.Body, &con); err != nil { + return nil, err + } + + return &con, nil +} + +// UpdateCustomTLSConfigurationInput is used as input to the UpdateCustomTLSConfiguration function. +type UpdateCustomTLSConfigurationInput struct { + ID string + Name string `jsonapi:"attr,name"` +} + +// UpdateCustomTLSConfiguration can only be used to change the name of the configuration +func (c *Client) UpdateCustomTLSConfiguration(i *UpdateCustomTLSConfigurationInput) (*CustomTLSConfiguration, error) { + if i.ID == "" { + return nil, ErrMissingID + } + + if i.Name == "" { + return nil, ErrMissingName + } + + path := fmt.Sprintf("/tls/configurations/%s", i.ID) + resp, err := c.PatchJSONAPI(path, i, nil) + if err != nil { + return nil, err + } + + var con CustomTLSConfiguration + if err := jsonapi.UnmarshalPayload(resp.Body, &con); err != nil { + return nil, err + } + return &con, nil +} diff --git a/vendor/github.com/fastly/go-fastly/v2/fastly/errors.go b/vendor/github.com/fastly/go-fastly/v2/fastly/errors.go index cbab4b9e5..c426f768c 100644 --- a/vendor/github.com/fastly/go-fastly/v2/fastly/errors.go +++ b/vendor/github.com/fastly/go-fastly/v2/fastly/errors.go @@ -169,6 +169,18 @@ var ErrMissingCertBlob = errors.New("missing required field 'CertBlob'") // a "IntermediatesBlob" key, but one was not set. var ErrMissingIntermediatesBlob = errors.New("missing required field 'IntermediatesBlob'") +// ErrMissingTLSCertificate is an error that is returned from an input struct that requires +// a "Certificate" field assigned a "TLSCertificate" struct, but one was not set. +var ErrMissingTLSCertificate = errors.New("missing required field 'Certificate'") + +// ErrMissingTLSConfiguration is an error that is returned from an input struct that requires +// a "Configuration" field assigned a "TLSConfiguration" struct, but one was not set. +var ErrMissingTLSConfiguration = errors.New("missing required field 'Configuration'") + +// ErrMissingTLSDomain is an error that is returned from an input struct that requires +// a "Domain" field assigned a "TLSDomain" struct, but one was not set. +var ErrMissingTLSDomain = errors.New("missing required field 'Domain'") + // ErrStatusNotOk is an error that indicates that indicates that the response body returned // by the Fastly API was not `{"status": "ok"}` var ErrStatusNotOk = errors.New("unexpected 'status' field in API response body") diff --git a/vendor/github.com/fastly/go-fastly/v2/fastly/ftp.go b/vendor/github.com/fastly/go-fastly/v2/fastly/ftp.go index 21340a44a..1bd1dbbb2 100644 --- a/vendor/github.com/fastly/go-fastly/v2/fastly/ftp.go +++ b/vendor/github.com/fastly/go-fastly/v2/fastly/ftp.go @@ -20,6 +20,7 @@ type FTP struct { PublicKey string `mapstructure:"public_key"` Path string `mapstructure:"path"` Period uint `mapstructure:"period"` + CompressionCodec string `mapstructure:"compression_codec"` GzipLevel uint8 `mapstructure:"gzip_level"` Format string `mapstructure:"format"` FormatVersion uint `mapstructure:"format_version"` @@ -92,6 +93,7 @@ type CreateFTPInput struct { Path string `form:"path,omitempty"` Period uint `form:"period,omitempty"` FormatVersion uint `form:"format_version,omitempty"` + CompressionCodec string `form:"compression_codec,omitempty"` GzipLevel uint8 `form:"gzip_level,omitempty"` Format string `form:"format,omitempty"` ResponseCondition string `form:"response_condition,omitempty"` @@ -182,6 +184,7 @@ type UpdateFTPInput struct { Path *string `form:"path,omitempty"` Period *uint `form:"period,omitempty"` FormatVersion *uint `form:"format_version,omitempty"` + CompressionCodec *string `form:"compression_codec,omitempty"` GzipLevel *uint8 `form:"gzip_level,omitempty"` Format *string `form:"format,omitempty"` ResponseCondition *string `form:"response_condition,omitempty"` diff --git a/vendor/github.com/fastly/go-fastly/v2/fastly/gcs.go b/vendor/github.com/fastly/go-fastly/v2/fastly/gcs.go index d5ab15081..202607c0d 100644 --- a/vendor/github.com/fastly/go-fastly/v2/fastly/gcs.go +++ b/vendor/github.com/fastly/go-fastly/v2/fastly/gcs.go @@ -18,6 +18,7 @@ type GCS struct { SecretKey string `mapstructure:"secret_key"` Path string `mapstructure:"path"` Period uint `mapstructure:"period"` + CompressionCodec string `mapstructure:"compression_codec"` GzipLevel uint8 `mapstructure:"gzip_level"` Format string `mapstructure:"format"` FormatVersion uint `mapstructure:"format_version"` @@ -88,6 +89,7 @@ type CreateGCSInput struct { Path string `form:"path,omitempty"` Period uint `form:"period,omitempty"` FormatVersion uint `form:"format_version,omitempty"` + CompressionCodec string `form:"compression_codec,omitempty"` GzipLevel uint8 `form:"gzip_level,omitempty"` Format string `form:"format,omitempty"` MessageType string `form:"message_type,omitempty"` @@ -176,6 +178,7 @@ type UpdateGCSInput struct { Path *string `form:"path,omitempty"` Period *uint `form:"period,omitempty"` FormatVersion *uint `form:"format_version,omitempty"` + CompressionCodec *string `form:"compression_codec,omitempty"` GzipLevel *uint8 `form:"gzip_level,omitempty"` Format *string `form:"format,omitempty"` MessageType *string `form:"message_type,omitempty"` diff --git a/vendor/github.com/fastly/go-fastly/v2/fastly/kinesis.go b/vendor/github.com/fastly/go-fastly/v2/fastly/kinesis.go new file mode 100644 index 000000000..f8138b59f --- /dev/null +++ b/vendor/github.com/fastly/go-fastly/v2/fastly/kinesis.go @@ -0,0 +1,242 @@ +package fastly + +import ( + "fmt" + "net/url" + "sort" + "time" +) + +// Kinesis represents a Kinesis response from the Fastly API. +type Kinesis struct { + ServiceID string `mapstructure:"service_id"` + ServiceVersion int `mapstructure:"version"` + + Name string `mapstructure:"name"` + StreamName string `mapstructure:"topic"` + Region string `mapstructure:"region"` + AccessKey string `mapstructure:"access_key"` + SecretKey string `mapstructure:"secret_key"` + Format string `mapstructure:"format"` + FormatVersion uint `mapstructure:"format_version"` + ResponseCondition string `mapstructure:"response_condition"` + Placement string `mapstructure:"placement"` + CreatedAt *time.Time `mapstructure:"created_at"` + UpdatedAt *time.Time `mapstructure:"updated_at"` + DeletedAt *time.Time `mapstructure:"deleted_at"` +} + +// kinesesByName is a sortable list of Kineses. +type kinesesByName []*Kinesis + +// Len, Swap, and Less implement the sortable interface. +func (s kinesesByName) Len() int { return len(s) } +func (s kinesesByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s kinesesByName) Less(i, j int) bool { + return s[i].Name < s[j].Name +} + +// ListKinesesInput is used as input to the ListKineses function. +type ListKinesesInput struct { + // ServiceID is the ID of the service (required). + ServiceID string + + // ServiceVersion is the specific configuration version (required). + ServiceVersion int +} + +// ListKineses returns the list of Kineses for the configuration version. +func (c *Client) ListKineses(i *ListKinesesInput) ([]*Kinesis, error) { + if i.ServiceID == "" { + return nil, ErrMissingServiceID + } + + if i.ServiceVersion == 0 { + return nil, ErrMissingServiceVersion + } + + path := fmt.Sprintf("/service/%s/version/%d/logging/kinesis", i.ServiceID, i.ServiceVersion) + resp, err := c.Get(path, nil) + if err != nil { + return nil, err + } + + var kineses []*Kinesis + if err := decodeBodyMap(resp.Body, &kineses); err != nil { + return nil, err + } + sort.Stable(kinesesByName(kineses)) + return kineses, nil +} + +// CreateKinesisInput is used as input to the CreateKinesis function. +type CreateKinesisInput struct { + // ServiceID is the ID of the service (required). + ServiceID string + + // ServiceVersion is the specific configuration version (required). + ServiceVersion int + + Name string `form:"name,omitempty"` + StreamName string `form:"topic,omitempty"` + Region string `form:"region,omitempty"` + AccessKey string `form:"access_key,omitempty"` + SecretKey string `form:"secret_key,omitempty"` + Format string `form:"format,omitempty"` + FormatVersion uint `form:"format_version,omitempty"` + ResponseCondition string `form:"response_condition,omitempty"` + Placement string `form:"placement,omitempty"` +} + +// CreateKinesis creates a new Fastly Kinesis. +func (c *Client) CreateKinesis(i *CreateKinesisInput) (*Kinesis, error) { + if i.ServiceID == "" { + return nil, ErrMissingServiceID + } + + if i.ServiceVersion == 0 { + return nil, ErrMissingServiceVersion + } + + path := fmt.Sprintf("/service/%s/version/%d/logging/kinesis", i.ServiceID, i.ServiceVersion) + resp, err := c.PostForm(path, i, nil) + if err != nil { + return nil, err + } + + var kinesis *Kinesis + if err := decodeBodyMap(resp.Body, &kinesis); err != nil { + return nil, err + } + return kinesis, nil +} + +// GetKinesisInput is used as input to the GetKinesis function. +type GetKinesisInput struct { + // ServiceID is the ID of the service (required). + ServiceID string + + // ServiceVersion is the specific configuration version (required). + ServiceVersion int + + // Name is the name of the Kinesis logging object to fetch (required). + Name string +} + +// GetKinesis gets the Kinesis configuration with the given parameters. +func (c *Client) GetKinesis(i *GetKinesisInput) (*Kinesis, error) { + if i.ServiceID == "" { + return nil, ErrMissingServiceID + } + + if i.ServiceVersion == 0 { + return nil, ErrMissingServiceVersion + } + + if i.Name == "" { + return nil, ErrMissingName + } + + path := fmt.Sprintf("/service/%s/version/%d/logging/kinesis/%s", i.ServiceID, i.ServiceVersion, url.PathEscape(i.Name)) + resp, err := c.Get(path, nil) + if err != nil { + return nil, err + } + + var kinesis *Kinesis + if err := decodeBodyMap(resp.Body, &kinesis); err != nil { + return nil, err + } + return kinesis, nil +} + +// UpdateKinesisInput is used as input to the UpdateKinesis function. +type UpdateKinesisInput struct { + // ServiceID is the ID of the service (required). + ServiceID string + + // ServiceVersion is the specific configuration version (required). + ServiceVersion int + + // Name is the name of the Kinesis logging object to update (required). + Name string + + NewName *string `form:"name,omitempty"` + StreamName *string `form:"topic,omitempty"` + Region *string `form:"region,omitempty"` + AccessKey *string `form:"access_key,omitempty"` + SecretKey *string `form:"secret_key,omitempty"` + Format *string `form:"format,omitempty"` + FormatVersion *uint `form:"format_version,omitempty"` + ResponseCondition *string `form:"response_condition,omitempty"` + Placement *string `form:"placement,omitempty"` +} + +// UpdateKinesis updates a specific Kinesis. +func (c *Client) UpdateKinesis(i *UpdateKinesisInput) (*Kinesis, error) { + if i.ServiceID == "" { + return nil, ErrMissingServiceID + } + + if i.ServiceVersion == 0 { + return nil, ErrMissingServiceVersion + } + + if i.Name == "" { + return nil, ErrMissingName + } + + path := fmt.Sprintf("/service/%s/version/%d/logging/kinesis/%s", i.ServiceID, i.ServiceVersion, url.PathEscape(i.Name)) + resp, err := c.PutForm(path, i, nil) + if err != nil { + return nil, err + } + + var kinesis *Kinesis + if err := decodeBodyMap(resp.Body, &kinesis); err != nil { + return nil, err + } + return kinesis, nil +} + +// DeleteKinesisInput is the input parameter to DeleteKinesis. +type DeleteKinesisInput struct { + // ServiceID is the ID of the service (required). + ServiceID string + + // ServiceVersion is the specific configuration version (required). + ServiceVersion int + + // Name is the name of the Kinesis logging object to delete (required). + Name string +} + +// DeleteKinesis deletes the given Kinesis version. +func (c *Client) DeleteKinesis(i *DeleteKinesisInput) error { + if i.ServiceID == "" { + return ErrMissingServiceID + } + + if i.ServiceVersion == 0 { + return ErrMissingServiceVersion + } + + if i.Name == "" { + return ErrMissingName + } + + path := fmt.Sprintf("/service/%s/version/%d/logging/kinesis/%s", i.ServiceID, i.ServiceVersion, url.PathEscape(i.Name)) + resp, err := c.Delete(path, nil) + if err != nil { + return err + } + + var r *statusResp + if err := decodeBodyMap(resp.Body, &r); err != nil { + return err + } + if !r.Ok() { + return ErrNotOK + } + return nil +} diff --git a/vendor/github.com/fastly/go-fastly/v2/fastly/openstack.go b/vendor/github.com/fastly/go-fastly/v2/fastly/openstack.go index 83da6cf62..defa681f3 100644 --- a/vendor/github.com/fastly/go-fastly/v2/fastly/openstack.go +++ b/vendor/github.com/fastly/go-fastly/v2/fastly/openstack.go @@ -20,6 +20,7 @@ type Openstack struct { Path string `mapstructure:"path"` Placement string `mapstructure:"placement"` Period uint `mapstructure:"period"` + CompressionCodec string `mapstructure:"compression_codec"` GzipLevel uint `mapstructure:"gzip_level"` Format string `mapstructure:"format"` FormatVersion uint `mapstructure:"format_version"` @@ -91,6 +92,7 @@ type CreateOpenstackInput struct { Path string `form:"path,omitempty"` Placement string `form:"placement,omitempty"` Period uint `form:"period,omitempty"` + CompressionCodec string `form:"compression_codec,omitempty"` GzipLevel uint `form:"gzip_level,omitempty"` Format string `form:"format,omitempty"` FormatVersion uint `form:"format_version,omitempty"` @@ -181,6 +183,7 @@ type UpdateOpenstackInput struct { Path *string `form:"path,omitempty"` Placement *string `form:"placement,omitempty"` Period *uint `form:"period,omitempty"` + CompressionCodec *string `form:"compression_codec,omitempty"` GzipLevel *uint `form:"gzip_level,omitempty"` Format *string `form:"format,omitempty"` FormatVersion *uint `form:"format_version,omitempty"` diff --git a/vendor/github.com/fastly/go-fastly/v2/fastly/s3.go b/vendor/github.com/fastly/go-fastly/v2/fastly/s3.go index 162b5b07f..719c73bc9 100644 --- a/vendor/github.com/fastly/go-fastly/v2/fastly/s3.go +++ b/vendor/github.com/fastly/go-fastly/v2/fastly/s3.go @@ -29,6 +29,7 @@ type S3 struct { SecretKey string `mapstructure:"secret_key"` Path string `mapstructure:"path"` Period uint `mapstructure:"period"` + CompressionCodec string `mapstructure:"compression_codec"` GzipLevel uint `mapstructure:"gzip_level"` Format string `mapstructure:"format"` FormatVersion uint `mapstructure:"format_version"` @@ -103,6 +104,7 @@ type CreateS3Input struct { SecretKey string `form:"secret_key,omitempty"` Path string `form:"path,omitempty"` Period uint `form:"period,omitempty"` + CompressionCodec string `form:"compression_codec,omitempty"` GzipLevel uint `form:"gzip_level,omitempty"` Format string `form:"format,omitempty"` MessageType string `form:"message_type,omitempty"` @@ -200,6 +202,7 @@ type UpdateS3Input struct { SecretKey *string `form:"secret_key,omitempty"` Path *string `form:"path,omitempty"` Period *uint `form:"period,omitempty"` + CompressionCodec *string `form:"compression_codec,omitempty"` GzipLevel *uint `form:"gzip_level,omitempty"` Format *string `form:"format,omitempty"` FormatVersion *uint `form:"format_version,omitempty"` diff --git a/vendor/github.com/fastly/go-fastly/v2/fastly/sftp.go b/vendor/github.com/fastly/go-fastly/v2/fastly/sftp.go index ce7aace0e..2d9f3e275 100644 --- a/vendor/github.com/fastly/go-fastly/v2/fastly/sftp.go +++ b/vendor/github.com/fastly/go-fastly/v2/fastly/sftp.go @@ -22,6 +22,7 @@ type SFTP struct { SSHKnownHosts string `mapstructure:"ssh_known_hosts"` Path string `mapstructure:"path"` Period uint `mapstructure:"period"` + CompressionCodec string `mapstructure:"compression_codec"` GzipLevel uint8 `mapstructure:"gzip_level"` Format string `mapstructure:"format"` FormatVersion uint `mapstructure:"format_version"` @@ -96,6 +97,7 @@ type CreateSFTPInput struct { Path string `form:"path,omitempty"` Period uint `form:"period,omitempty"` FormatVersion uint `form:"format_version,omitempty"` + CompressionCodec string `form:"compression_codec,omitempty"` GzipLevel uint `form:"gzip_level,omitempty"` Format string `form:"format,omitempty"` ResponseCondition string `form:"response_condition,omitempty"` @@ -188,6 +190,7 @@ type UpdateSFTPInput struct { Path *string `form:"path,omitempty"` Period *uint `form:"period,omitempty"` FormatVersion *uint `form:"format_version,omitempty"` + CompressionCodec *string `form:"compression_codec,omitempty"` GzipLevel *uint `form:"gzip_level,omitempty"` Format *string `form:"format,omitempty"` ResponseCondition *string `form:"response_condition,omitempty"` diff --git a/vendor/github.com/fastly/go-fastly/v2/fastly/splunk.go b/vendor/github.com/fastly/go-fastly/v2/fastly/splunk.go index db2a893de..c04993ecd 100644 --- a/vendor/github.com/fastly/go-fastly/v2/fastly/splunk.go +++ b/vendor/github.com/fastly/go-fastly/v2/fastly/splunk.go @@ -14,6 +14,8 @@ type Splunk struct { Name string `mapstructure:"name"` URL string `mapstructure:"url"` + RequestMaxEntries uint `mapstructure:"request_max_entries"` + RequestMaxBytes uint `mapstructure:"request_max_bytes"` Format string `mapstructure:"format"` FormatVersion uint `mapstructure:"format_version"` ResponseCondition string `mapstructure:"response_condition"` @@ -21,6 +23,8 @@ type Splunk struct { Token string `mapstructure:"token"` TLSCACert string `mapstructure:"tls_ca_cert"` TLSHostname string `mapstructure:"tls_hostname"` + TLSClientCert string `mapstructure:"tls_client_cert"` + TLSClientKey string `mapstructure:"tls_client_key"` CreatedAt *time.Time `mapstructure:"created_at"` UpdatedAt *time.Time `mapstructure:"updated_at"` DeletedAt *time.Time `mapstructure:"deleted_at"` @@ -79,6 +83,8 @@ type CreateSplunkInput struct { Name string `form:"name,omitempty"` URL string `form:"url,omitempty"` + RequestMaxEntries uint `form:"request_max_entries,omitempty"` + RequestMaxBytes uint `form:"request_max_bytes,omitempty"` Format string `form:"format,omitempty"` FormatVersion uint `form:"format_version,omitempty"` ResponseCondition string `form:"response_condition,omitempty"` @@ -86,6 +92,8 @@ type CreateSplunkInput struct { Token string `form:"token,omitempty"` TLSCACert string `form:"tls_ca_cert,omitempty"` TLSHostname string `form:"tls_hostname,omitempty"` + TLSClientCert string `form:"tls_client_cert,omitempty"` + TLSClientKey string `form:"tls_client_key,omitempty"` } // CreateSplunk creates a new Fastly splunk. @@ -163,6 +171,8 @@ type UpdateSplunkInput struct { NewName *string `form:"name,omitempty"` URL *string `form:"url,omitempty"` + RequestMaxEntries *uint `form:"request_max_entries,omitempty"` + RequestMaxBytes *uint `form:"request_max_bytes,omitempty"` Format *string `form:"format,omitempty"` FormatVersion *uint `form:"format_version,omitempty"` ResponseCondition *string `form:"response_condition,omitempty"` @@ -170,6 +180,8 @@ type UpdateSplunkInput struct { Token *string `form:"token,omitempty"` TLSCACert *string `form:"tls_ca_cert,omitempty"` TLSHostname *string `form:"tls_hostname,omitempty"` + TLSClientCert *string `form:"tls_client_cert,omitempty"` + TLSClientKey *string `form:"tls_client_key,omitempty"` } // UpdateSplunk updates a specific splunk. diff --git a/vendor/modules.txt b/vendor/modules.txt index 6d32d4278..0226c0ef8 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -59,7 +59,7 @@ github.com/bgentry/go-netrc/netrc github.com/bgentry/speakeasy # github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew/spew -# github.com/fastly/go-fastly/v2 v2.0.0 +# github.com/fastly/go-fastly/v2 v2.1.0 ## explicit github.com/fastly/go-fastly/v2/fastly # github.com/fatih/color v1.7.0 diff --git a/website/docs/r/service_compute.html.markdown b/website/docs/r/service_compute.html.markdown index e4973cf3e..1a99a8440 100644 --- a/website/docs/r/service_compute.html.markdown +++ b/website/docs/r/service_compute.html.markdown @@ -8,7 +8,7 @@ description: |- # fastly_service_compute -Provides a Fastly Compute@Edge service. Compute@Edge is a computation platform capable of running custom binaries that you compile on your own systems and upload to Fastly. Security and portability is provided by compiling your code to [WebAssembly](https://webassembly.org/), which is ran at the edge using [Lucet](https://github.com/bytecodealliance/lucet), an open-source WebAssembly runtime created by Fastly. A compute service encompasses Domains and Backends. +Provides a Fastly Compute@Edge service. Compute@Edge is a computation platform capable of running custom binaries that you compile on your own systems and upload to Fastly. Security and portability is provided by compiling your code to [WebAssembly](https://webassembly.org/), which is run at the edge using [Lucet](https://github.com/bytecodealliance/lucet), an open-source WebAssembly runtime created by Fastly. A compute service encompasses Domains and Backends. The Service resource requires a domain name that is correctly set up to direct traffic to the Fastly service. See Fastly's guide on [Adding CNAME Records][fastly-cname] @@ -111,6 +111,8 @@ order to destroy the Service, set `force_destroy` to `true`. Default `false`. [Defined below](#logging_digitalocean-block). * `logging_cloudfiles` - (Optional) A Rackspace Cloud Files endpoint to send streaming logs to. [Defined below](#logging_cloudfiles-block). +* `logging_kinesis` - (Optional) A Kinesis endpoint to send streaming logs to. +[Defined below](#logging_kinesis-block). ### domain block @@ -522,6 +524,17 @@ The `logging_cloudfiles` block supports: * `timestamp_format` - (Optional) The strftime specified timestamp formatting (default `%Y-%m-%dT%H:%M:%S.000`). +### logging_kinesis block + +The `logging_kinesis` block supports: + +* `name` - (Required) The unique name of the Kinesis logging endpoint. +* `topic` - (Required) The Kinesis stream name. +* `region` - (Optional) The AWS region the stream resides in. (Default: `us-east-1`). +* `access_key` - (Required) The AWS access key to be used to write to the stream. +* `secret_key` - (Required) The AWS secret access key to authenticate with. + + ## Attributes Reference In addition to the arguments listed above, the following attributes are exported: diff --git a/website/docs/r/service_v1.html.markdown b/website/docs/r/service_v1.html.markdown index 8a0a60401..88d92f792 100644 --- a/website/docs/r/service_v1.html.markdown +++ b/website/docs/r/service_v1.html.markdown @@ -291,6 +291,8 @@ order to destroy the Service, set `force_destroy` to `true`. Default `false`. [Defined below](#logging_digitalocean-block). * `logging_cloudfiles` - (Optional) A Rackspace Cloud Files endpoint to send streaming logs to. [Defined below](#logging_cloudfiles-block). +* `logging_kinesis` - (Optional) A Kinesis endpoint to send streaming logs to. +[Defined below](#logging_kinesis-block). * `response_object` - (Optional) Allows you to create synthetic responses that exist entirely on the varnish machine. Useful for creating error or maintenance pages that exists outside the scope of your datacenter. Best when used with Condition objects. [Defined below](#response_object-block) * `snippet` - (Optional) A set of custom, "regular" (non-dynamic) VCL Snippet configuration blocks. @@ -888,6 +890,20 @@ The `logging_cloudfiles` block supports: * `placement` - (Optional) Where in the generated VCL the logging call should be placed. Can be `none` or `waf_debug`. * `response_condition` - (Optional) The name of an existing condition in the configured endpoint, or leave blank to always execute. +### logging_kinesis block + +The `logging_kinesis` block supports: + +* `name` - (Required) The unique name of the Kinesis logging endpoint. +* `topic` - (Required) The Kinesis stream name. +* `region` - (Optional) The AWS region the stream resides in. (Default: `us-east-1`). +* `access_key` - (Required) The AWS access key to be used to write to the stream. +* `secret_key` - (Required) The AWS secret access key to authenticate with. +* `format` - (Optional) Apache style log formatting. +* `format_version` - (Optional) The version of the custom logging format used for the configured endpoint. Can be either `1` or `2`. (default: `2`). +* `placement` - (Optional) Where in the generated VCL the logging call should be placed. Can be `none` or `waf_debug`. +* `response_condition` - (Optional) The name of an existing condition in the configured endpoint, or leave blank to always execute. + ### response_object block The `response_object` block supports: @@ -988,4 +1004,3 @@ Fastly Service can be imported using their service ID, e.g. ``` $ terraform import fastly_service_v1.demo xxxxxxxxxxxxxxxxxxxx ``` - diff --git a/website_src/docs/r/arguments/logging_kinesis.markdown.tmpl b/website_src/docs/r/arguments/logging_kinesis.markdown.tmpl new file mode 100644 index 000000000..598fdd24b --- /dev/null +++ b/website_src/docs/r/arguments/logging_kinesis.markdown.tmpl @@ -0,0 +1,17 @@ +{{define "logging_kinesis"}}* `logging_kinesis` - (Optional) A Kinesis endpoint to send streaming logs to. +[Defined below](#logging_kinesis-block).{{end}} + +{{define "logging_kinesis_block"}} +### logging_kinesis block + +The `logging_kinesis` block supports: + +* `name` - (Required) The unique name of the Kinesis logging endpoint. +* `topic` - (Required) The Kinesis stream name. +* `region` - (Optional) The AWS region the stream resides in. (Default: `us-east-1`). +* `access_key` - (Required) The AWS access key to be used to write to the stream. +* `secret_key` - (Required) The AWS secret access key to authenticate with. +{{ if eq .Data.ServiceType "vcl"}}* `format` - (Optional) Apache style log formatting. +* `format_version` - (Optional) The version of the custom logging format used for the configured endpoint. Can be either `1` or `2`. (default: `2`). +* `placement` - (Optional) Where in the generated VCL the logging call should be placed. Can be `none` or `waf_debug`. +* `response_condition` - (Optional) The name of an existing condition in the configured endpoint, or leave blank to always execute.{{end}}{{end}} diff --git a/website_src/docs/r/service_compute.html.markdown.tmpl b/website_src/docs/r/service_compute.html.markdown.tmpl index af3eb46a3..025613908 100644 --- a/website_src/docs/r/service_compute.html.markdown.tmpl +++ b/website_src/docs/r/service_compute.html.markdown.tmpl @@ -80,6 +80,7 @@ The following arguments are supported: {{ template "logging_openstack" . }} {{ template "logging_digitalocean" . }} {{ template "logging_cloudfiles" . }} +{{ template "logging_kinesis" . }} {{ template "domain_block" . }} {{ template "backend_block" . }} @@ -110,6 +111,7 @@ The following arguments are supported: {{ template "logging_openstack_block" . }} {{ template "logging_digitalocean_block" . }} {{ template "logging_cloudfiles_block" . }} +{{ template "logging_kinesis_block" . }} {{ template "export_intro" .}} {{ template "footer" .}} diff --git a/website_src/docs/r/service_v1.html.markdown.tmpl b/website_src/docs/r/service_v1.html.markdown.tmpl index d09e8a97c..fd52ef537 100644 --- a/website_src/docs/r/service_v1.html.markdown.tmpl +++ b/website_src/docs/r/service_v1.html.markdown.tmpl @@ -253,6 +253,7 @@ The following arguments are supported: {{ template "logging_openstack" . }} {{ template "logging_digitalocean" . }} {{ template "logging_cloudfiles" . }} +{{ template "logging_kinesis" . }} {{ template "response_object" . }} {{ template "snippet" . }} {{ template "dynamicsnippet" . }} @@ -294,6 +295,7 @@ The following arguments are supported: {{ template "logging_openstack_block" . }} {{ template "logging_digitalocean_block" . }} {{ template "logging_cloudfiles_block" . }} +{{ template "logging_kinesis_block" . }} {{ template "response_object_block" . }} {{ template "snippet_block" . }} {{ template "dynamicsnippet_block" . }}