From a800fdaf50c297e729f917a64d04d8c916ccb87f Mon Sep 17 00:00:00 2001 From: obs-gh-alexlew <153021320+obs-gh-alexlew@users.noreply.github.com> Date: Tue, 30 Jan 2024 11:00:55 -0800 Subject: [PATCH] feat: add timestamp support to http poller (#101) --- client/internal/meta/operation/poller.graphql | 7 ++ client/meta/genqlient.generated.go | 67 +++++++++- client/meta/helpers.go | 18 +++ docs/resources/poller.md | 16 +++ observe/resource_poller.go | 115 ++++++++++++++++++ observe/resource_poller_test.go | 55 +++++++++ 6 files changed, 275 insertions(+), 3 deletions(-) diff --git a/client/internal/meta/operation/poller.graphql b/client/internal/meta/operation/poller.graphql index 4e42135b..d754175b 100644 --- a/client/internal/meta/operation/poller.graphql +++ b/client/internal/meta/operation/poller.graphql @@ -54,6 +54,13 @@ fragment Poller on Poller { type } } + timestamps { + name + source + format + offset + truncate + } } ... on PollerGCPMonitoringConfig { projectId diff --git a/client/meta/genqlient.generated.go b/client/meta/genqlient.generated.go index 1bbcec73..831cc8a4 100644 --- a/client/meta/genqlient.generated.go +++ b/client/meta/genqlient.generated.go @@ -4847,9 +4847,10 @@ type PollerConfigPollerHTTPConfig struct { ContentType *string `json:"contentType"` Headers *types.JsonObject `json:"headers"` // Default HTTP request configuration that will be used for all requests. Keys declared in requests will override these values. - Template *HttpRequestConfig `json:"template"` - Requests []HttpRequestConfig `json:"requests"` - Rules []PollerConfigPollerHTTPConfigRulesPollerHTTPRuleConfig `json:"rules"` + Template *HttpRequestConfig `json:"template"` + Requests []HttpRequestConfig `json:"requests"` + Rules []PollerConfigPollerHTTPConfigRulesPollerHTTPRuleConfig `json:"rules"` + Timestamps []PollerConfigPollerHTTPConfigTimestampsPollerHTTPTimestampConfig `json:"timestamps"` } // GetTypename returns PollerConfigPollerHTTPConfig.Typename, and is useful for accessing the field via an interface. @@ -4896,6 +4897,11 @@ func (v *PollerConfigPollerHTTPConfig) GetRules() []PollerConfigPollerHTTPConfig return v.Rules } +// GetTimestamps returns PollerConfigPollerHTTPConfig.Timestamps, and is useful for accessing the field via an interface. +func (v *PollerConfigPollerHTTPConfig) GetTimestamps() []PollerConfigPollerHTTPConfigTimestampsPollerHTTPTimestampConfig { + return v.Timestamps +} + // PollerConfigPollerHTTPConfigRulesPollerHTTPRuleConfig includes the requested fields of the GraphQL type PollerHTTPRuleConfig. type PollerConfigPollerHTTPConfigRulesPollerHTTPRuleConfig struct { Match *HttpRequestConfig `json:"match"` @@ -4926,6 +4932,40 @@ func (v *PollerConfigPollerHTTPConfigRulesPollerHTTPRuleConfigDecoderPollerHTTPD return v.Type } +// PollerConfigPollerHTTPConfigTimestampsPollerHTTPTimestampConfig includes the requested fields of the GraphQL type PollerHTTPTimestampConfig. +type PollerConfigPollerHTTPConfigTimestampsPollerHTTPTimestampConfig struct { + Name *string `json:"name"` + Source *string `json:"source"` + Format *PollerHTTPTimestampFormatScheme `json:"format"` + Offset *string `json:"offset"` + Truncate *string `json:"truncate"` +} + +// GetName returns PollerConfigPollerHTTPConfigTimestampsPollerHTTPTimestampConfig.Name, and is useful for accessing the field via an interface. +func (v *PollerConfigPollerHTTPConfigTimestampsPollerHTTPTimestampConfig) GetName() *string { + return v.Name +} + +// GetSource returns PollerConfigPollerHTTPConfigTimestampsPollerHTTPTimestampConfig.Source, and is useful for accessing the field via an interface. +func (v *PollerConfigPollerHTTPConfigTimestampsPollerHTTPTimestampConfig) GetSource() *string { + return v.Source +} + +// GetFormat returns PollerConfigPollerHTTPConfigTimestampsPollerHTTPTimestampConfig.Format, and is useful for accessing the field via an interface. +func (v *PollerConfigPollerHTTPConfigTimestampsPollerHTTPTimestampConfig) GetFormat() *PollerHTTPTimestampFormatScheme { + return v.Format +} + +// GetOffset returns PollerConfigPollerHTTPConfigTimestampsPollerHTTPTimestampConfig.Offset, and is useful for accessing the field via an interface. +func (v *PollerConfigPollerHTTPConfigTimestampsPollerHTTPTimestampConfig) GetOffset() *string { + return v.Offset +} + +// GetTruncate returns PollerConfigPollerHTTPConfigTimestampsPollerHTTPTimestampConfig.Truncate, and is useful for accessing the field via an interface. +func (v *PollerConfigPollerHTTPConfigTimestampsPollerHTTPTimestampConfig) GetTruncate() *string { + return v.Truncate +} + // PollerConfigPollerMongoDBAtlasConfig includes the requested fields of the GraphQL type PollerMongoDBAtlasConfig. type PollerConfigPollerMongoDBAtlasConfig struct { Typename *string `json:"__typename"` @@ -10852,6 +10892,13 @@ fragment Poller on Poller { type } } + timestamps { + name + source + format + offset + truncate + } } ... on PollerGCPMonitoringConfig { projectId @@ -13689,6 +13736,13 @@ fragment Poller on Poller { type } } + timestamps { + name + source + format + offset + truncate + } } ... on PollerGCPMonitoringConfig { projectId @@ -16489,6 +16543,13 @@ fragment Poller on Poller { type } } + timestamps { + name + source + format + offset + truncate + } } ... on PollerGCPMonitoringConfig { projectId diff --git a/client/meta/helpers.go b/client/meta/helpers.go index 932076ed..d1b4d87f 100644 --- a/client/meta/helpers.go +++ b/client/meta/helpers.go @@ -83,6 +83,24 @@ var AllPollerHTTPRequestAuthSchemes = []PollerHTTPRequestAuthScheme{ PollerHTTPRequestAuthSchemeDigest, } +var AllPollerHTTPTimestampFormats = []PollerHTTPTimestampFormatScheme{ + PollerHTTPTimestampFormatSchemeAnsic, + PollerHTTPTimestampFormatSchemeUnixdate, + PollerHTTPTimestampFormatSchemeRubydate, + PollerHTTPTimestampFormatSchemeRfc822, + PollerHTTPTimestampFormatSchemeRfc822z, + PollerHTTPTimestampFormatSchemeRfc850, + PollerHTTPTimestampFormatSchemeRfc1123, + PollerHTTPTimestampFormatSchemeRfc1123z, + PollerHTTPTimestampFormatSchemeRfc3339, + PollerHTTPTimestampFormatSchemeRfc3339nano, + PollerHTTPTimestampFormatSchemeKitchen, + PollerHTTPTimestampFormatSchemeUnix, + PollerHTTPTimestampFormatSchemeUnixmilli, + PollerHTTPTimestampFormatSchemeUnixmicro, + PollerHTTPTimestampFormatSchemeUnixmano, +} + // AllBookmarkKindTypes This list is incomplete and will be filled in // as we support more types of bookmarks in the terraform provider var AllBookmarkKindTypes = []BookmarkKind{ diff --git a/docs/resources/poller.md b/docs/resources/poller.md index 4aa3217e..0dcb006f 100644 --- a/docs/resources/poller.md +++ b/docs/resources/poller.md @@ -118,6 +118,7 @@ Optional: - `request` (Block List) (see [below for nested schema](#nestedblock--http--request)) - `rule` (Block List) (see [below for nested schema](#nestedblock--http--rule)) - `template` (Block List, Max: 1) (see [below for nested schema](#nestedblock--http--template)) +- `timestamp` (Block List) (see [below for nested schema](#nestedblock--http--timestamp)) ### Nested Schema for `http.request` @@ -185,6 +186,21 @@ Optional: - `username` (String) + +### Nested Schema for `http.timestamp` + +Required: + +- `name` (String) + +Optional: + +- `format` (String) +- `offset` (String) +- `source` (String) +- `truncate` (String) + + ### Nested Schema for `mongodbatlas` diff --git a/observe/resource_poller.go b/observe/resource_poller.go index 67132d6a..4c6698aa 100644 --- a/observe/resource_poller.go +++ b/observe/resource_poller.go @@ -273,6 +273,37 @@ func resourcePoller() *schema.Resource { }, }, }, + "timestamp": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "source": { + Type: schema.TypeString, + Optional: true, + }, + "format": { + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: validateEnums(gql.AllPollerHTTPTimestampFormats), + }, + "offset": { + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: validateTimeDuration, + }, + "truncate": { + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: validateTimeDuration, + }, + }, + }, + }, }, }, }, @@ -414,6 +445,7 @@ func newPollerConfig(data *schema.ResourceData) (input *gql.PollerInput, diags d Headers: &parsedHeaders, Requests: expandPollerHTTPRequests(data, "http.0.request"), Rules: expandPollerHTTPRules(data, "http.0.rule"), + Timestamps: expandPollerHTTPTimestamps(data, "http.0.timestamp"), } if v, ok := data.GetOk("http.0.endpoint"); ok { @@ -623,6 +655,12 @@ func resourcePollerRead(ctx context.Context, data *schema.ResourceData, meta int ht["rule"] = rule } + timestamp, timestampDiags := flattenPollerHTTPTimestamps(httpConfig.Timestamps) + diags = append(diags, timestampDiags...) + if !requestDiags.HasError() { + ht["timestamp"] = timestamp + } + if err := data.Set("http", []interface{}{ht}); err != nil { diags = append(diags, diag.FromErr(err)...) } @@ -889,3 +927,80 @@ func expandPollerHTTPDecoder(data *schema.ResourceData, key string) *gql.PollerH } return decoder } + +func flattenPollerHTTPTimestamps(timestamps []gql.PollerConfigPollerHTTPConfigTimestampsPollerHTTPTimestampConfig) (flats []map[string]interface{}, diags diag.Diagnostics) { + if len(timestamps) == 0 { + return + } + + for _, t := range timestamps { + timestamp, diag := flattenPollerHTTPTimestamp(&t) + diags = append(diags, diag...) + if !diag.HasError() { + flats = append(flats, timestamp) + } + } + + return +} + +func flattenPollerHTTPTimestamp(timestamp *gql.PollerConfigPollerHTTPConfigTimestampsPollerHTTPTimestampConfig) (flat map[string]interface{}, diags diag.Diagnostics) { + if timestamp == nil { + return + } + + flat = map[string]interface{}{ + "name": timestamp.Name, + "source": timestamp.Source, + "format": timestamp.Format, + "offset": timestamp.Offset, + "truncate": timestamp.Truncate, + } + + return +} + +func expandPollerHTTPTimestamps(data *schema.ResourceData, key string) (timestamps []gql.PollerHTTPTimestampInput) { + l := data.Get(key).([]interface{}) + if len(l) == 0 { + return nil + } + + for i := range l { + if req := expandPollerHTTPTimestamp(data, fmt.Sprintf("%s.%d", key, i)); req != nil { + timestamps = append(timestamps, *req) + } + } + return +} + +func expandPollerHTTPTimestamp(data *schema.ResourceData, key string) *gql.PollerHTTPTimestampInput { + if _, ok := data.GetOk(key); !ok { + return nil + } + + timestamp := &gql.PollerHTTPTimestampInput{} + + if v, ok := data.GetOk(key + ".name"); ok { + s := v.(string) + timestamp.Name = &s + } + if v, ok := data.GetOk(key + ".source"); ok { + s := v.(string) + timestamp.Source = &s + } + if v, ok := data.GetOk(key + ".format"); ok { + s := gql.PollerHTTPTimestampFormatScheme(v.(string)) + timestamp.Format = &s + } + if v, ok := data.GetOk(key + ".offset"); ok { + s := v.(string) + timestamp.Offset = &s + } + if v, ok := data.GetOk(key + ".truncate"); ok { + s := v.(string) + timestamp.Truncate = &s + } + + return timestamp +} diff --git a/observe/resource_poller_test.go b/observe/resource_poller_test.go index 04bb9caa..41a0061f 100644 --- a/observe/resource_poller_test.go +++ b/observe/resource_poller_test.go @@ -465,6 +465,61 @@ func TestAccObservePollerHTTP(t *testing.T) { resource.TestCheckResourceAttrSet("observe_poller.first", "datastream"), ), }, + { + Config: fmt.Sprintf(configPreamble+` + resource "observe_datastream" "example" { + workspace = data.observe_workspace.default.oid + name = "%s-%s" + icon_url = "test" + } + resource "observe_poller" "timestamp" { + workspace = data.observe_workspace.default.oid + name = "%s-%s" + interval = "1m" + retries = 5 + datastream = observe_datastream.example.oid + skip_external_validation = true + + http { + request { + username = "user" + password = "pass" + auth_scheme = "Digest" + url = "https://example.com/path" + } + + timestamp { + name = "now" + format = "RFC822" + truncate = "1s" + } + + timestamp { + name = "start" + source = "now" + format = "RFC822" + offset = "1h" + truncate = "1s" + } + } + }`, randomPrefix, "pollers", randomPrefix, "http"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("observe_poller.timestamp", "name", randomPrefix+"-http"), + resource.TestCheckResourceAttr("observe_poller.timestamp", "kind", "HTTP"), + resource.TestCheckResourceAttr("observe_poller.timestamp", "interval", "1m0s"), + resource.TestCheckResourceAttr("observe_poller.timestamp", "http.0.template.#", "0"), + resource.TestCheckResourceAttr("observe_poller.timestamp", "http.0.request.0.url", "https://example.com/path"), + resource.TestCheckResourceAttr("observe_poller.timestamp", "http.0.request.0.auth_scheme", "Digest"), + resource.TestCheckResourceAttr("observe_poller.timestamp", "http.0.timestamp.0.name", "now"), + resource.TestCheckResourceAttr("observe_poller.timestamp", "http.0.timestamp.0.format", "RFC822"), + resource.TestCheckResourceAttr("observe_poller.timestamp", "http.0.timestamp.0.truncate", "1s"), + resource.TestCheckResourceAttr("observe_poller.timestamp", "http.0.timestamp.1.name", "start"), + resource.TestCheckResourceAttr("observe_poller.timestamp", "http.0.timestamp.1.source", "now"), + resource.TestCheckResourceAttr("observe_poller.timestamp", "http.0.timestamp.1.format", "RFC822"), + resource.TestCheckResourceAttr("observe_poller.timestamp", "http.0.timestamp.1.offset", "1h"), + resource.TestCheckResourceAttr("observe_poller.timestamp", "http.0.timestamp.1.truncate", "1s"), + ), + }, }, }) }