From 51a328a648e7bcf61304c182d7b3495667dd4700 Mon Sep 17 00:00:00 2001 From: Jacob Hull Date: Fri, 20 May 2022 15:46:53 -0700 Subject: [PATCH] feat: add new resource for keys api Introduces a new logdna_key resource to interact with the keys api to manage service and ingestion keys. This change includes some additional upkeep changes: * Update github.com/hashicorp/terraform-plugin-sdk/v2 to v2.15.0 * Remove duplicate code around existence testing * Have requests use the http client attached to the provider instead of creating a new one each time * Ensure all tests respect the env API_URL * Fix memory reference error when testing existence of non-existent resource Ref: LOG-12483 Signed-off-by: Jacob Hull jacob@planethull.com --- docs/resources/logdna_key.md | 61 ++++++++ logdna/common_test.go | 19 +++ logdna/data_source_alert_test.go | 10 +- logdna/provider.go | 1 + logdna/provider_test.go | 1 + logdna/request.go | 5 +- logdna/request_test.go | 3 +- logdna/resource_alert_test.go | 74 ++++------ logdna/resource_archive_test.go | 27 +--- logdna/resource_category_test.go | 30 +--- logdna/resource_ingestion_exclusion_test.go | 21 +-- logdna/resource_key.go | 145 ++++++++++++++++++++ logdna/resource_key_test.go | 87 ++++++++++++ logdna/resource_stream_config_test.go | 23 +--- logdna/resource_stream_exclusion_test.go | 29 +--- logdna/resource_view_test.go | 99 ++++++------- logdna/response_types.go | 7 + 17 files changed, 428 insertions(+), 214 deletions(-) create mode 100644 docs/resources/logdna_key.md create mode 100644 logdna/resource_key.go create mode 100644 logdna/resource_key_test.go diff --git a/docs/resources/logdna_key.md b/docs/resources/logdna_key.md new file mode 100644 index 0000000..2432650 --- /dev/null +++ b/docs/resources/logdna_key.md @@ -0,0 +1,61 @@ +# Resource: `logdna_key` + +This resource allows you to manage ingestion and service keys. + +## Example + +```hcl +provider "logdna" { + servicekey = "xxxxxxxxxxxxxxxxxxxxxxxx" +} + +resource "logdna_key" "service-key" { + type = "service" + + lifecycle { + create_before_destroy = true + } +} + +resource "logdna_key" "ingestion-key" { + type = "ingestion" + + lifecycle { + create_before_destroy = true + } +} +``` + +The `create_before_destroy` and `lifecycle` meta-argument are not required, but ensure a valid key is always available so there's no disruption of service. + +## Key Rotation + +This resource can be used in conjuction with automated scripts to perform automatic key rotations, e.g., + +```sh +# Run this every time you want to rotate the key +$ terraform apply -replace="logdna_key.my_key" +``` + +## Argument Reference + +The following arguments are supported: + +- `type`: **string** _(Required)_ The type of key to be used. Should be either `service` or `ingestion`. + +## Attributes Reference + +In addition to all the arguments above, the following attributes are exported: + +- `id`: **string** The unique identifier of this key. +- `key`: **string** The actual key value. +- `type`: **string** The type of key. +- `created`: **int** The date the key was created in Unix time milliseconds. + +## Import + +A key can be imported using the `id`, e.g., + +```sh +$ terraform import logdna_key.my_key +``` diff --git a/logdna/common_test.go b/logdna/common_test.go index f51c221..154a74f 100644 --- a/logdna/common_test.go +++ b/logdna/common_test.go @@ -4,6 +4,9 @@ import ( "fmt" "regexp" "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) const tmplPc = `provider "logdna" { @@ -148,3 +151,19 @@ func fmtBlockArgs(nstLvl int, opts map[string]string) string { } return blkCfg.String() } + +func testResourceExists(rsType string, rsName string) resource.TestCheckFunc { + identifier := fmt.Sprintf("logdna_%s.%s", rsType, rsName) + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[identifier] + if !ok { + return fmt.Errorf("Not found: %s", identifier) + } + if rs.Primary.ID == "" { + return fmt.Errorf("No ID set") + } + + return nil + } +} diff --git a/logdna/data_source_alert_test.go b/logdna/data_source_alert_test.go index f7f81a2..1c82c27 100644 --- a/logdna/data_source_alert_test.go +++ b/logdna/data_source_alert_test.go @@ -19,25 +19,25 @@ func TestDataAlert_BulkChannels(t *testing.T) { "email": cloneDefaults(chnlDefaults["email"]), "email1": cloneDefaults(chnlDefaults["email"]), } - emsCfg := fmtTestConfigResource("alert", "test", nilLst, alertDefaults, emArgs, nilLst) + emsCfg := fmtTestConfigResource("alert", "test", globalPcArgs, alertDefaults, emArgs, nilLst) pdArgs := map[string]map[string]string{ "pagerduty": cloneDefaults(chnlDefaults["pagerduty"]), "pagerduty1": cloneDefaults(chnlDefaults["pagerduty"]), } - pdsCfg := fmtTestConfigResource("alert", "test", nilLst, alertDefaults, pdArgs, nilLst) + pdsCfg := fmtTestConfigResource("alert", "test", globalPcArgs, alertDefaults, pdArgs, nilLst) slArgs := map[string]map[string]string{ "slack": cloneDefaults(chnlDefaults["slack"]), "slack1": cloneDefaults(chnlDefaults["slack"]), } - slsCfg := fmtTestConfigResource("alert", "test", nilLst, alertDefaults, slArgs, nilLst) + slsCfg := fmtTestConfigResource("alert", "test", globalPcArgs, alertDefaults, slArgs, nilLst) wbArgs := map[string]map[string]string{ "webhook": cloneDefaults(chnlDefaults["webhook"]), "webhook1": cloneDefaults(chnlDefaults["webhook"]), } - wbsCfg := fmtTestConfigResource("alert", "test", nilLst, alertDefaults, wbArgs, nilLst) + wbsCfg := fmtTestConfigResource("alert", "test", globalPcArgs, alertDefaults, wbArgs, nilLst) resource.Test(t, resource.TestCase{ Providers: testAccProviders, @@ -104,7 +104,7 @@ func TestDataSourceAlert_MultipleChannels(t *testing.T) { "slack": cloneDefaults(chnlDefaults["slack"]), "webhook": cloneDefaults(chnlDefaults["webhook"]), } - fmtCfg := fmt.Sprintf("%s\n%s", fmtTestConfigResource("alert", "test", nilLst, alertDefaults, chArgs, nilLst), ds) + fmtCfg := fmt.Sprintf("%s\n%s", fmtTestConfigResource("alert", "test", globalPcArgs, alertDefaults, chArgs, nilLst), ds) resource.Test(t, resource.TestCase{ Providers: testAccProviders, diff --git a/logdna/provider.go b/logdna/provider.go index 8c24be9..e1c0652 100644 --- a/logdna/provider.go +++ b/logdna/provider.go @@ -38,6 +38,7 @@ func Provider() *schema.Provider { "logdna_stream_exclusion": resourceStreamExclusion(), "logdna_ingestion_exclusion": resourceIngestionExclusion(), "logdna_archive": resourceArchiveConfig(), + "logdna_key": resourceKey(), }, ConfigureFunc: providerConfigure, } diff --git a/logdna/provider_test.go b/logdna/provider_test.go index e2b770c..e7887e6 100644 --- a/logdna/provider_test.go +++ b/logdna/provider_test.go @@ -9,6 +9,7 @@ import ( var serviceKey = os.Getenv("SERVICE_KEY") var apiHostUrl = os.Getenv("API_URL") +var globalPcArgs = []string {serviceKey, apiHostUrl} var testAccProviders map[string]*schema.Provider var testAccProvider *schema.Provider diff --git a/logdna/request.go b/logdna/request.go index 0cd57b8..9da6c0a 100644 --- a/logdna/request.go +++ b/logdna/request.go @@ -7,7 +7,6 @@ import ( "io" "io/ioutil" "net/http" - "time" ) type httpRequest func(string, string, io.Reader) (*http.Request, error) @@ -32,8 +31,8 @@ type requestConfig struct { // newRequestConfig abstracts the struct creation to allow for mocking func newRequestConfig(pc *providerConfig, method string, uri string, body interface{}, mutators ...func(*requestConfig)) *requestConfig { rc := &requestConfig{ - serviceKey: pc.serviceKey, - httpClient: &http.Client{Timeout: 15 * time.Second}, + serviceKey: pc.serviceKey, + httpClient: pc.httpClient, apiURL: fmt.Sprintf("%s%s", pc.baseURL, uri), // uri should have a preceding slash (/) method: method, body: body, diff --git a/logdna/request_test.go b/logdna/request_test.go index a9f3d75..c5cc9c9 100644 --- a/logdna/request_test.go +++ b/logdna/request_test.go @@ -10,6 +10,7 @@ import ( "net/http/httptest" "strings" "testing" + "time" "github.com/stretchr/testify/assert" ) @@ -40,7 +41,7 @@ func setJSONMarshal(customMarshaller jsonMarshal) func(*requestConfig) { func TestRequest_MakeRequest(t *testing.T) { assert := assert.New(t) - pc := providerConfig{serviceKey: "abc123"} + pc := providerConfig{serviceKey: "abc123", httpClient: &http.Client{Timeout: 15 * time.Second}} resourceID := "test123456" t.Run("Server receives proper method, URL, and headers", func(t *testing.T) { diff --git a/logdna/resource_alert_test.go b/logdna/resource_alert_test.go index f8a5a98..48a39e9 100644 --- a/logdna/resource_alert_test.go +++ b/logdna/resource_alert_test.go @@ -1,12 +1,10 @@ package logdna import ( - "fmt" "regexp" "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) var alertDefaults = cloneDefaults(rsDefaults["alert"]) @@ -33,7 +31,7 @@ func TestAlert_ErrorResourceName(t *testing.T) { Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: fmtTestConfigResource("alert", "new", nilLst, args, nilOpt, nilLst), + Config: fmtTestConfigResource("alert", "new", globalPcArgs, args, nilOpt, nilLst), ExpectError: regexp.MustCompile("The argument \"name\" is required, but no definition was found."), }, }, @@ -43,23 +41,23 @@ func TestAlert_ErrorResourceName(t *testing.T) { func TestAlert_ErrorsChannel(t *testing.T) { imArgs := map[string]map[string]string{"email": cloneDefaults(chnlDefaults["email"])} imArgs["email"]["immediate"] = `"not a bool"` - immdte := fmtTestConfigResource("alert", "new", nilLst, alertDefaults, imArgs, nilLst) + immdte := fmtTestConfigResource("alert", "new", globalPcArgs, alertDefaults, imArgs, nilLst) opArgs := map[string]map[string]string{"pagerduty": cloneDefaults(chnlDefaults["pagerduty"])} opArgs["pagerduty"]["operator"] = `1000` - opratr := fmtTestConfigResource("alert", "new", nilLst, alertDefaults, opArgs, nilLst) + opratr := fmtTestConfigResource("alert", "new", globalPcArgs, alertDefaults, opArgs, nilLst) trArgs := map[string]map[string]string{"webhook": cloneDefaults(chnlDefaults["webhook"])} trArgs["webhook"]["terminal"] = `"invalid"` - trmnal := fmtTestConfigResource("alert", "new", nilLst, alertDefaults, trArgs, nilLst) + trmnal := fmtTestConfigResource("alert", "new", globalPcArgs, alertDefaults, trArgs, nilLst) tiArgs := map[string]map[string]string{"email": cloneDefaults(chnlDefaults["email"])} tiArgs["email"]["triggerinterval"] = `18` - tintvl := fmtTestConfigResource("alert", "new", nilLst, alertDefaults, tiArgs, nilLst) + tintvl := fmtTestConfigResource("alert", "new", globalPcArgs, alertDefaults, tiArgs, nilLst) tlArgs := map[string]map[string]string{"slack": cloneDefaults(chnlDefaults["slack"])} tlArgs["slack"]["triggerlimit"] = `0` - tlimit := fmtTestConfigResource("alert", "new", nilLst, alertDefaults, tlArgs, nilLst) + tlimit := fmtTestConfigResource("alert", "new", globalPcArgs, alertDefaults, tlArgs, nilLst) resource.Test(t, resource.TestCase{ Providers: testAccProviders, @@ -91,11 +89,11 @@ func TestAlert_ErrorsChannel(t *testing.T) { func TestAlert_ErrorsEmailChannel(t *testing.T) { msArgs := map[string]map[string]string{"email": cloneDefaults(chnlDefaults["email"])} msArgs["email"]["emails"] = "" - misngE := fmtTestConfigResource("alert", "new", nilLst, alertDefaults, msArgs, nilLst) + misngE := fmtTestConfigResource("alert", "new", globalPcArgs, alertDefaults, msArgs, nilLst) inArgs := map[string]map[string]string{"email": cloneDefaults(chnlDefaults["email"])} inArgs["email"]["emails"] = `"not an array of strings"` - invldE := fmtTestConfigResource("alert", "new", nilLst, alertDefaults, inArgs, nilLst) + invldE := fmtTestConfigResource("alert", "new", globalPcArgs, alertDefaults, inArgs, nilLst) resource.Test(t, resource.TestCase{ Providers: testAccProviders, @@ -120,7 +118,7 @@ func TestAlert_ErrorsPagerDutyChannel(t *testing.T) { Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: fmtTestConfigResource("alert", "new", nilLst, alertDefaults, chArgs, nilLst), + Config: fmtTestConfigResource("alert", "new", globalPcArgs, alertDefaults, chArgs, nilLst), ExpectError: regexp.MustCompile("The argument \"key\" is required, but no definition was found."), }, }, @@ -130,11 +128,11 @@ func TestAlert_ErrorsPagerDutyChannel(t *testing.T) { func TestAlert_ErrorsSlackChannel(t *testing.T) { ulInvd := map[string]map[string]string{"slack": cloneDefaults(chnlDefaults["slack"])} ulInvd["slack"]["url"] = `"this is not a valid url"` - ulCfgE := fmtTestConfigResource("alert", "new", nilLst, alertDefaults, ulInvd, nilLst) + ulCfgE := fmtTestConfigResource("alert", "new", globalPcArgs, alertDefaults, ulInvd, nilLst) ulMsng := map[string]map[string]string{"slack": cloneDefaults(chnlDefaults["slack"])} ulMsng["slack"]["url"] = "" - ulCfgM := fmtTestConfigResource("alert", "new", nilLst, alertDefaults, ulMsng, nilLst) + ulCfgM := fmtTestConfigResource("alert", "new", globalPcArgs, alertDefaults, ulMsng, nilLst) resource.Test(t, resource.TestCase{ Providers: testAccProviders, @@ -154,19 +152,19 @@ func TestAlert_ErrorsSlackChannel(t *testing.T) { func TestAlert_ErrorsWebhookChannel(t *testing.T) { btArgs := map[string]map[string]string{"webhook": cloneDefaults(chnlDefaults["webhook"])} btArgs["webhook"]["bodytemplate"] = `"{\"test\": }"` - btCfgE := fmtTestConfigResource("alert", "new", nilLst, alertDefaults, btArgs, nilLst) + btCfgE := fmtTestConfigResource("alert", "new", globalPcArgs, alertDefaults, btArgs, nilLst) mdArgs := map[string]map[string]string{"webhook": cloneDefaults(chnlDefaults["webhook"])} mdArgs["webhook"]["method"] = `"false"` - mdCfgE := fmtTestConfigResource("alert", "new", nilLst, alertDefaults, mdArgs, nilLst) + mdCfgE := fmtTestConfigResource("alert", "new", globalPcArgs, alertDefaults, mdArgs, nilLst) ulInvd := map[string]map[string]string{"webhook": cloneDefaults(chnlDefaults["webhook"])} ulInvd["webhook"]["url"] = `"this is not a valid url"` - ulCfgE := fmtTestConfigResource("alert", "new", nilLst, alertDefaults, ulInvd, nilLst) + ulCfgE := fmtTestConfigResource("alert", "new", globalPcArgs, alertDefaults, ulInvd, nilLst) ulMsng := map[string]map[string]string{"webhook": cloneDefaults(chnlDefaults["webhook"])} ulMsng["webhook"]["url"] = "" - ulCfgM := fmtTestConfigResource("alert", "new", nilLst, alertDefaults, ulMsng, nilLst) + ulCfgM := fmtTestConfigResource("alert", "new", globalPcArgs, alertDefaults, ulMsng, nilLst) resource.Test(t, resource.TestCase{ Providers: testAccProviders, @@ -193,11 +191,11 @@ func TestAlert_ErrorsWebhookChannel(t *testing.T) { func TestAlert_Basic(t *testing.T) { chArgs := map[string]map[string]string{"email": cloneDefaults(chnlDefaults["email"])} - iniCfg := fmtTestConfigResource("alert", "new", nilLst, alertDefaults, chArgs, nilLst) + iniCfg := fmtTestConfigResource("alert", "new", globalPcArgs, alertDefaults, chArgs, nilLst) rsArgs := cloneDefaults(rsDefaults["alert"]) rsArgs["name"] = `"test2"` - updCfg := fmtTestConfigResource("alert", "new", nilLst, rsArgs, chArgs, nilLst) + updCfg := fmtTestConfigResource("alert", "new", globalPcArgs, rsArgs, chArgs, nilLst) resource.Test(t, resource.TestCase{ Providers: testAccProviders, @@ -205,7 +203,7 @@ func TestAlert_Basic(t *testing.T) { { Config: iniCfg, Check: resource.ComposeTestCheckFunc( - testAlertExists("logdna_alert.new"), + testResourceExists("alert", "new"), resource.TestCheckResourceAttr("logdna_alert.new", "name", "test"), resource.TestCheckResourceAttr("logdna_alert.new", "email_channel.#", "1"), resource.TestCheckResourceAttr("logdna_alert.new", "email_channel.0.%", "7"), @@ -225,7 +223,7 @@ func TestAlert_Basic(t *testing.T) { { Config: updCfg, Check: resource.ComposeTestCheckFunc( - testAlertExists("logdna_alert.new"), + testResourceExists("alert", "new"), resource.TestCheckResourceAttr("logdna_alert.new", "name", "test2"), ), }, @@ -243,25 +241,25 @@ func TestAlert_BulkChannels(t *testing.T) { "email": cloneDefaults(chnlDefaults["email"]), "email1": cloneDefaults(chnlDefaults["email"]), } - emsCfg := fmtTestConfigResource("alert", "new", nilLst, alertDefaults, emArgs, nilLst) + emsCfg := fmtTestConfigResource("alert", "new", globalPcArgs, alertDefaults, emArgs, nilLst) pdArgs := map[string]map[string]string{ "pagerduty": cloneDefaults(chnlDefaults["pagerduty"]), "pagerduty1": cloneDefaults(chnlDefaults["pagerduty"]), } - pdsCfg := fmtTestConfigResource("alert", "new", nilLst, alertDefaults, pdArgs, nilLst) + pdsCfg := fmtTestConfigResource("alert", "new", globalPcArgs, alertDefaults, pdArgs, nilLst) slArgs := map[string]map[string]string{ "slack": cloneDefaults(chnlDefaults["slack"]), "slack1": cloneDefaults(chnlDefaults["slack"]), } - slsCfg := fmtTestConfigResource("alert", "new", nilLst, alertDefaults, slArgs, nilLst) + slsCfg := fmtTestConfigResource("alert", "new", globalPcArgs, alertDefaults, slArgs, nilLst) wbArgs := map[string]map[string]string{ "webhook": cloneDefaults(chnlDefaults["webhook"]), "webhook1": cloneDefaults(chnlDefaults["webhook"]), } - wbsCfg := fmtTestConfigResource("alert", "new", nilLst, alertDefaults, wbArgs, nilLst) + wbsCfg := fmtTestConfigResource("alert", "new", globalPcArgs, alertDefaults, wbArgs, nilLst) resource.Test(t, resource.TestCase{ Providers: testAccProviders, @@ -269,7 +267,7 @@ func TestAlert_BulkChannels(t *testing.T) { { Config: emsCfg, Check: resource.ComposeTestCheckFunc( - testAlertExists("logdna_alert.new"), + testResourceExists("alert", "new"), resource.TestCheckResourceAttr("logdna_alert.new", "name", "test"), resource.TestCheckResourceAttr("logdna_alert.new", "email_channel.#", "2"), resource.TestCheckResourceAttr("logdna_alert.new", "email_channel.0.%", "7"), @@ -282,7 +280,7 @@ func TestAlert_BulkChannels(t *testing.T) { { Config: pdsCfg, Check: resource.ComposeTestCheckFunc( - testAlertExists("logdna_alert.new"), + testResourceExists("alert", "new"), resource.TestCheckResourceAttr("logdna_alert.new", "name", "test"), resource.TestCheckResourceAttr("logdna_alert.new", "pagerduty_channel.#", "2"), resource.TestCheckResourceAttr("logdna_alert.new", "pagerduty_channel.0.%", "6"), @@ -295,7 +293,7 @@ func TestAlert_BulkChannels(t *testing.T) { { Config: slsCfg, Check: resource.ComposeTestCheckFunc( - testAlertExists("logdna_alert.new"), + testResourceExists("alert", "new"), resource.TestCheckResourceAttr("logdna_alert.new", "name", "test"), resource.TestCheckResourceAttr("logdna_alert.new", "slack_channel.#", "2"), resource.TestCheckResourceAttr("logdna_alert.new", "slack_channel.0.%", "6"), @@ -308,7 +306,7 @@ func TestAlert_BulkChannels(t *testing.T) { { Config: wbsCfg, Check: resource.ComposeTestCheckFunc( - testAlertExists("logdna_alert.new"), + testResourceExists("alert", "new"), resource.TestCheckResourceAttr("logdna_alert.new", "name", "test"), resource.TestCheckResourceAttr("logdna_alert.new", "webhook_channel.#", "2"), resource.TestCheckResourceAttr("logdna_alert.new", "webhook_channel.0.%", "9"), @@ -334,9 +332,9 @@ func TestAlert_MultipleChannels(t *testing.T) { Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: fmtTestConfigResource("alert", "new", nilLst, alertDefaults, chArgs, nilLst), + Config: fmtTestConfigResource("alert", "new", globalPcArgs, alertDefaults, chArgs, nilLst), Check: resource.ComposeTestCheckFunc( - testAlertExists("logdna_alert.new"), + testResourceExists("alert", "new"), resource.TestCheckResourceAttr("logdna_alert.new", "name", "test"), resource.TestCheckResourceAttr("logdna_alert.new", "email_channel.#", "1"), resource.TestCheckResourceAttr("logdna_alert.new", "email_channel.0.emails.#", "1"), @@ -387,17 +385,3 @@ func TestAlert_MultipleChannels(t *testing.T) { }, }) } - -func testAlertExists(n string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if rs.Primary.ID == "" { - return fmt.Errorf("No ID set") - } - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - return nil - } -} diff --git a/logdna/resource_archive_test.go b/logdna/resource_archive_test.go index c409de6..585ab1e 100644 --- a/logdna/resource_archive_test.go +++ b/logdna/resource_archive_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) var s3Bucket = os.Getenv("S3_BUCKET") @@ -57,7 +56,7 @@ func TestArchiveConfig_expectInvalidIntegrationError(t *testing.T) { { Config: testArchiveConfig(` integration = "invalid" - `, ""), + `, apiHostUrl), ExpectError: regexp.MustCompile(`"integration" must be one of \[ibm s3 azblob gcs dos swift\]`), }, }, @@ -73,7 +72,7 @@ func TestArchiveConfig_expectMissingFieldError(t *testing.T) { integration = "s3" s3_config { } - `, ""), + `, apiHostUrl), ExpectError: regexp.MustCompile("Missing required argument"), }, }, @@ -91,9 +90,9 @@ func TestArchiveConfig_basic(t *testing.T) { s3_config { bucket = "%s" } - `, s3Bucket), ""), + `, s3Bucket), apiHostUrl), Check: resource.ComposeTestCheckFunc( - testArchiveConfigExists("logdna_archive.archive"), + testResourceExists("archive", "archive"), resource.TestCheckResourceAttr("logdna_archive.archive", "integration", "s3"), resource.TestCheckResourceAttr("logdna_archive.archive", "s3_config.0.bucket", s3Bucket), ), @@ -105,9 +104,9 @@ func TestArchiveConfig_basic(t *testing.T) { bucket = "%s" projectid = "%s" } - `, gcsBucket, gcsProjectid), ""), + `, gcsBucket, gcsProjectid), apiHostUrl), Check: resource.ComposeTestCheckFunc( - testArchiveConfigExists("logdna_archive.archive"), + testResourceExists("archive", "archive"), resource.TestCheckResourceAttr("logdna_archive.archive", "integration", "gcs"), resource.TestCheckResourceAttr("logdna_archive.archive", "gcs_config.0.bucket", gcsBucket), resource.TestCheckResourceAttr("logdna_archive.archive", "gcs_config.0.projectid", gcsProjectid), @@ -122,20 +121,6 @@ func TestArchiveConfig_basic(t *testing.T) { }) } -func testArchiveConfigExists(n string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if rs.Primary.ID == "" { - return fmt.Errorf("No ID set") - } - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - return nil - } -} - func testArchiveConfig(fields string, url string) string { uc := "" if url != "" { diff --git a/logdna/resource_category_test.go b/logdna/resource_category_test.go index fcbdf25..eaeb8c9 100644 --- a/logdna/resource_category_test.go +++ b/logdna/resource_category_test.go @@ -1,13 +1,11 @@ package logdna import ( - "fmt" "regexp" "testing" "strings" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) func TestCategory_ErrorProviderUrl(t *testing.T) { @@ -37,7 +35,7 @@ func TestCategory_ErrorResourceName(t *testing.T) { Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: fmtTestConfigResource("category", "new", nilLst, catArgs, nilOpt, nilLst), + Config: fmtTestConfigResource("category", "new", globalPcArgs, catArgs, nilOpt, nilLst), ExpectError: regexp.MustCompile("The argument \"name\" is required, but no definition was found."), }, }, @@ -54,8 +52,8 @@ func TestCategory_ErrorResourceType(t *testing.T) { Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: fmtTestConfigResource("category", "new", nilLst, catArgs, nilOpt, nilLst), - ExpectError: regexp.MustCompile("Error: POST https://api.logdna.com/v1/config/categories/incorrect, status 400 NOT OK!"), + Config: fmtTestConfigResource("category", "new", globalPcArgs, catArgs, nilOpt, nilLst), + ExpectError: regexp.MustCompile("Error: POST .+?, status 400 NOT OK!"), }, }, }) @@ -77,17 +75,17 @@ func TestCategory_Basic(t *testing.T) { Steps: []resource.TestStep{ { // NOTE It tests a category create operation - Config: fmtTestConfigResource("category", "new-category", nilLst, catInsArgs, nilOpt, nilLst), + Config: fmtTestConfigResource("category", "new-category", globalPcArgs, catInsArgs, nilOpt, nilLst), Check: resource.ComposeTestCheckFunc( - testCategoryExists("logdna_category.new-category"), + testResourceExists("category", "new-category"), resource.TestCheckResourceAttr("logdna_category.new-category", "name", strings.Replace(catInsArgs["name"], "\"", "", 2)), ), }, { // NOTE It tests a category update operation - Config: fmtTestConfigResource("category", "new-category", nilLst, catUpdArgs, nilOpt, nilLst), + Config: fmtTestConfigResource("category", "new-category", globalPcArgs, catUpdArgs, nilOpt, nilLst), Check: resource.ComposeTestCheckFunc( - testCategoryExists("logdna_category.new-category"), + testResourceExists("category", "new-category"), resource.TestCheckResourceAttr("logdna_category.new-category", "name", strings.Replace(catUpdArgs["name"], "\"", "", 2)), ), }, @@ -99,17 +97,3 @@ func TestCategory_Basic(t *testing.T) { }, }) } - -func testCategoryExists(n string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if rs.Primary.ID == "" { - return fmt.Errorf("No ID set") - } - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - return nil - } -} diff --git a/logdna/resource_ingestion_exclusion_test.go b/logdna/resource_ingestion_exclusion_test.go index 8391a66..60c735b 100644 --- a/logdna/resource_ingestion_exclusion_test.go +++ b/logdna/resource_ingestion_exclusion_test.go @@ -6,7 +6,6 @@ import ( "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) func TestIngestionExclusion_expectInvalidURLError(t *testing.T) { @@ -64,7 +63,7 @@ func TestIngestionExclusion_basic(t *testing.T) { query = "foo bar" `, apiHostUrl), Check: resource.ComposeTestCheckFunc( - testIngestionExclusionExists("logdna_ingestion_exclusion.new"), + testResourceExists("ingestion_exclusion", "new"), resource.TestCheckResourceAttr("logdna_ingestion_exclusion.new", "title", "test-title"), resource.TestCheckResourceAttr("logdna_ingestion_exclusion.new", "active", "true"), resource.TestCheckResourceAttr("logdna_ingestion_exclusion.new", "apps.#", "2"), @@ -91,7 +90,7 @@ func TestIngestionExclusion_basic(t *testing.T) { query = "foo bar" `, apiHostUrl), Check: resource.ComposeTestCheckFunc( - testIngestionExclusionExists("logdna_ingestion_exclusion.new"), + testResourceExists("ingestion_exclusion", "new"), resource.TestCheckResourceAttr("logdna_ingestion_exclusion.new", "title", "test-title-update"), resource.TestCheckResourceAttr("logdna_ingestion_exclusion.new", "active", "false"), resource.TestCheckResourceAttr("logdna_ingestion_exclusion.new", "apps.#", "2"), @@ -110,7 +109,7 @@ func TestIngestionExclusion_basic(t *testing.T) { query = "foo bar" `, apiHostUrl), Check: resource.ComposeTestCheckFunc( - testIngestionExclusionExists("logdna_ingestion_exclusion.new"), + testResourceExists("ingestion_exclusion", "new"), resource.TestCheckResourceAttr("logdna_ingestion_exclusion.new", "hosts.#", "0"), ), }, @@ -123,20 +122,6 @@ func TestIngestionExclusion_basic(t *testing.T) { }) } -func testIngestionExclusionExists(n string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if rs.Primary.ID == "" { - return fmt.Errorf("No ID set") - } - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - return nil - } -} - func testIngestionExclusion(fields string, url string) string { uc := "" if url != "" { diff --git a/logdna/resource_key.go b/logdna/resource_key.go new file mode 100644 index 0000000..af30a51 --- /dev/null +++ b/logdna/resource_key.go @@ -0,0 +1,145 @@ +package logdna + +import ( + "context" + "encoding/json" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceKeyCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + pc := m.(*providerConfig) + + keyType := d.Get("type").(string) + + req := newRequestConfig( + pc, + "POST", + fmt.Sprintf("/v1/config/keys?type=%s", keyType), + nil, + ) + + body, err := req.MakeRequest() + log.Printf("[DEBUG] %s %s, payload is: %s", req.method, req.apiURL, body) + + if err != nil { + return diag.FromErr(err) + } + + createdKey := keyResponse{} + err = json.Unmarshal(body, &createdKey) + if err != nil { + return diag.FromErr(err) + } + log.Printf("[DEBUG] After %s key, the created key is %+v", req.method, createdKey) + + d.SetId(createdKey.KeyID) + + return resourceKeyRead(ctx, d, m) +} + +func resourceKeyRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + var diags diag.Diagnostics + + pc := m.(*providerConfig) + keyID := d.Id() + + req := newRequestConfig( + pc, + "GET", + fmt.Sprintf("/v1/config/keys/%s", keyID), + nil, + ) + + body, err := req.MakeRequest() + + log.Printf("[DEBUG] GET key raw response body %s\n", body) + if err != nil { + diags = append(diags, diag.Diagnostic{ + Severity: diag.Error, + Summary: "Cannot read the remote key resource", + Detail: err.Error(), + }) + return diags + } + + key := keyResponse{} + err = json.Unmarshal(body, &key) + if err != nil { + diags = append(diags, diag.Diagnostic{ + Severity: diag.Error, + Summary: "Cannot unmarshal response from the remote key resource", + Detail: err.Error(), + }) + return diags + } + log.Printf("[DEBUG] The GET key structure is as follows: %+v\n", key) + + // Top level keys can be set directly + appendError(d.Set("type", key.Type), &diags) + appendError(d.Set("id", key.KeyID), &diags) + appendError(d.Set("key", key.Key), &diags) + appendError(d.Set("created", key.Created), &diags) + + return diags +} + +func resourceKeyDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + pc := m.(*providerConfig) + keyID := d.Id() + + req := newRequestConfig( + pc, + "DELETE", + fmt.Sprintf("/v1/config/keys/%s", keyID), + nil, + ) + + body, err := req.MakeRequest() + log.Printf("[DEBUG] %s %s key %s", req.method, req.apiURL, body) + + if err != nil { + return diag.FromErr(err) + } + + d.SetId("") + return nil +} + +func resourceKey() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceKeyCreate, + ReadContext: resourceKeyRead, + DeleteContext: resourceKeyDelete, + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + ForceNew: true, + Required: true, + }, + "id": { + Type: schema.TypeString, + ForceNew: true, + Computed: true, + }, + "key": { + Type: schema.TypeString, + ForceNew: true, + Sensitive: true, + Computed: true, + }, + "created": { + Type: schema.TypeInt, + ForceNew: true, + Computed: true, + }, + }, + } +} diff --git a/logdna/resource_key_test.go b/logdna/resource_key_test.go new file mode 100644 index 0000000..81911e4 --- /dev/null +++ b/logdna/resource_key_test.go @@ -0,0 +1,87 @@ +package logdna + +import ( + "regexp" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestKey_ErrorResourceTypeUndefined(t *testing.T) { + args := map[string]string{} + + resource.Test(t, resource.TestCase{ + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: fmtTestConfigResource("key", "new", []string{serviceKey, apiHostUrl}, args, nilOpt, nilLst), + ExpectError: regexp.MustCompile("The argument \"type\" is required, but no definition was found."), + }, + }, + }) +} + +func TestKey_ErrorResourceTypeInvalid(t *testing.T) { + args := map[string]string{ + "type": `"incorrect"`, + } + + resource.Test(t, resource.TestCase{ + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: fmtTestConfigResource("key", "new", []string{serviceKey, apiHostUrl}, args, nilOpt, nilLst), + ExpectError: regexp.MustCompile("Error: POST .+?, status 400 NOT OK!"), + }, + }, + }) +} + +func TestKey_Basic(t *testing.T) { + serviceArgs := map[string]string{ + "type": `"service"`, + } + + ingestionArgs := map[string]string{ + "type": `"ingestion"`, + } + + resource.Test(t, resource.TestCase{ + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + // NOTE It tests a service key create operation + Config: fmtTestConfigResource("key", "new-service-key", []string{serviceKey, apiHostUrl}, serviceArgs, nilOpt, nilLst), + Check: resource.ComposeTestCheckFunc( + testResourceExists("key", "new-service-key"), + resource.TestCheckResourceAttr("logdna_key.new-service-key", "type", strings.Replace(serviceArgs["type"], "\"", "", 2)), + resource.TestCheckResourceAttrSet("logdna_key.new-service-key", "id"), + resource.TestCheckResourceAttrSet("logdna_key.new-service-key", "key"), + resource.TestCheckResourceAttrSet("logdna_key.new-service-key", "created"), + ), + }, + { + ResourceName: "logdna_key.new-service-key", + ImportState: true, + ImportStateVerify: true, + }, + { + // NOTE It tests an ingestion key create operation + Config: fmtTestConfigResource("key", "new-ingestion-key", []string{serviceKey, apiHostUrl}, ingestionArgs, nilOpt, nilLst), + Check: resource.ComposeTestCheckFunc( + testResourceExists("key", "new-ingestion-key"), + resource.TestCheckResourceAttr("logdna_key.new-ingestion-key", "type", strings.Replace(ingestionArgs["type"], "\"", "", 2)), + resource.TestCheckResourceAttrSet("logdna_key.new-ingestion-key", "id"), + resource.TestCheckResourceAttrSet("logdna_key.new-ingestion-key", "key"), + resource.TestCheckResourceAttrSet("logdna_key.new-ingestion-key", "created"), + ), + }, + { + ResourceName: "logdna_key.new-ingestion-key", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} diff --git a/logdna/resource_stream_config_test.go b/logdna/resource_stream_config_test.go index 111642e..c9a37f8 100644 --- a/logdna/resource_stream_config_test.go +++ b/logdna/resource_stream_config_test.go @@ -9,7 +9,6 @@ import ( "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/stretchr/testify/assert" ) @@ -40,7 +39,7 @@ func TestStreamConfig_expectInvalidBrokerError(t *testing.T) { topic = "test-topic" user = "test-user" password = "test-password" - `, ""), + `, apiHostUrl), ExpectError: regexp.MustCompile(`Failed to connect to Kafka broker`), }, }, @@ -57,7 +56,7 @@ func TestStreamConfig_expectInvalidConfigError(t *testing.T) { topic = "" user = "" password = "" - `, ""), + `, apiHostUrl), ExpectError: regexp.MustCompile(`\\"topic\\" is not allowed to be empty.*\\"user\\" is not allowed to be empty.*\\"password\\" is not allowed to be empty`), }, }, @@ -112,7 +111,7 @@ func TestStreamConfig_basic(t *testing.T) { `, brokers[0], brokers[1], topic, user, password, ), ts.URL), Check: resource.ComposeTestCheckFunc( - testStreamConfigExists("logdna_stream_config.stream"), + testResourceExists("stream_config", "stream"), resource.TestCheckResourceAttr("logdna_stream_config.stream", "topic", topic), resource.TestCheckResourceAttr("logdna_stream_config.stream", "user", user), resource.TestCheckResourceAttr("logdna_stream_config.stream", "status", "active"), @@ -134,7 +133,7 @@ func TestStreamConfig_basic(t *testing.T) { `, brokers[0], brokers[1], user, password, ), ts.URL), Check: resource.ComposeTestCheckFunc( - testStreamConfigExists("logdna_stream_config.stream"), + testResourceExists("stream_config", "stream"), resource.TestCheckResourceAttr("logdna_stream_config.stream", "topic", "updated"), ), }, @@ -150,20 +149,6 @@ func TestStreamConfig_basic(t *testing.T) { }) } -func testStreamConfigExists(n string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if rs.Primary.ID == "" { - return fmt.Errorf("No ID set") - } - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - return nil - } -} - func testStreamConfig(fields string, url string) string { uc := "" if url != "" { diff --git a/logdna/resource_stream_exclusion_test.go b/logdna/resource_stream_exclusion_test.go index 3b0dc1b..a158c2e 100644 --- a/logdna/resource_stream_exclusion_test.go +++ b/logdna/resource_stream_exclusion_test.go @@ -6,7 +6,6 @@ import ( "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) func TestStreamExclusion_expectInvalidURLError(t *testing.T) { @@ -38,7 +37,7 @@ func TestStreamExclusion_expectInvalidError(t *testing.T) { Config: testStreamExclusion(` title = "test-title" apps = [] - `, ""), + `, apiHostUrl), ExpectError: regexp.MustCompile("requires 1 item minimum, but config has only 0 declared"), }, }, @@ -62,9 +61,9 @@ func TestStreamExclusion_basic(t *testing.T) { "host-2" ] query = "query-foo AND query-bar" - `, ""), + `, apiHostUrl), Check: resource.ComposeTestCheckFunc( - testStreamExclusionExists("logdna_stream_exclusion.new"), + testResourceExists("stream_exclusion", "new"), resource.TestCheckResourceAttr("logdna_stream_exclusion.new", "title", "test-title"), resource.TestCheckResourceAttr("logdna_stream_exclusion.new", "active", "true"), resource.TestCheckResourceAttr("logdna_stream_exclusion.new", "apps.#", "2"), @@ -89,9 +88,9 @@ func TestStreamExclusion_basic(t *testing.T) { "host-2" ] query = "query-foo AND query-bar" - `, ""), + `, apiHostUrl), Check: resource.ComposeTestCheckFunc( - testStreamExclusionExists("logdna_stream_exclusion.new"), + testResourceExists("stream_exclusion", "new"), resource.TestCheckResourceAttr("logdna_stream_exclusion.new", "title", "test-title-update"), resource.TestCheckResourceAttr("logdna_stream_exclusion.new", "active", "false"), resource.TestCheckResourceAttr("logdna_stream_exclusion.new", "apps.#", "2"), @@ -108,9 +107,9 @@ func TestStreamExclusion_basic(t *testing.T) { "app-2" ] query = "query-foo AND query-bar" - `, ""), + `, apiHostUrl), Check: resource.ComposeTestCheckFunc( - testStreamExclusionExists("logdna_stream_exclusion.new"), + testResourceExists("stream_exclusion", "new"), resource.TestCheckResourceAttr("logdna_stream_exclusion.new", "hosts.#", "0"), ), }, @@ -123,20 +122,6 @@ func TestStreamExclusion_basic(t *testing.T) { }) } -func testStreamExclusionExists(n string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if rs.Primary.ID == "" { - return fmt.Errorf("No ID set") - } - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - return nil - } -} - func testStreamExclusion(fields string, url string) string { uc := "" if url != "" { diff --git a/logdna/resource_view_test.go b/logdna/resource_view_test.go index df03b63..ebf4f64 100644 --- a/logdna/resource_view_test.go +++ b/logdna/resource_view_test.go @@ -6,7 +6,6 @@ import ( "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" ) const ctgies = `["DEMOCATEGORY1", "DemoCategory2"]` @@ -30,27 +29,27 @@ func TestView_ErrorProviderUrl(t *testing.T) { func TestView_ErrorsResourceFields(t *testing.T) { nme := cloneDefaults(rsDefaults["view"]) nme["name"] = "" - nmeCfg := fmtTestConfigResource("view", "new", nilLst, nme, nilOpt, nilLst) + nmeCfg := fmtTestConfigResource("view", "new", globalPcArgs, nme, nilOpt, nilLst) app := cloneDefaults(rsDefaults["view"]) app["apps"] = `"invalid apps value"` - appCfg := fmtTestConfigResource("view", "new", nilLst, app, nilOpt, nilLst) + appCfg := fmtTestConfigResource("view", "new", globalPcArgs, app, nilOpt, nilLst) ctg := cloneDefaults(rsDefaults["view"]) ctg["categories"] = `"invalid categories value"` - ctgCfg := fmtTestConfigResource("view", "new", nilLst, ctg, nilOpt, nilLst) + ctgCfg := fmtTestConfigResource("view", "new", globalPcArgs, ctg, nilOpt, nilLst) hst := cloneDefaults(rsDefaults["view"]) hst["hosts"] = `"invalid hosts value"` - hstCfg := fmtTestConfigResource("view", "new", nilLst, hst, nilOpt, nilLst) + hstCfg := fmtTestConfigResource("view", "new", globalPcArgs, hst, nilOpt, nilLst) lvl := cloneDefaults(rsDefaults["view"]) lvl["levels"] = `"invalid levels value"` - lvlCfg := fmtTestConfigResource("view", "new", nilLst, lvl, nilOpt, nilLst) + lvlCfg := fmtTestConfigResource("view", "new", globalPcArgs, lvl, nilOpt, nilLst) tgs := cloneDefaults(rsDefaults["view"]) tgs["tags"] = `"invalid tags value"` - tgsCfg := fmtTestConfigResource("view", "new", nilLst, tgs, nilOpt, nilLst) + tgsCfg := fmtTestConfigResource("view", "new", globalPcArgs, tgs, nilOpt, nilLst) resource.Test(t, resource.TestCase{ Providers: testAccProviders, @@ -86,23 +85,23 @@ func TestView_ErrorsResourceFields(t *testing.T) { func TestView_ErrorsChannel(t *testing.T) { imArgs := map[string]map[string]string{"email": cloneDefaults(chnlDefaults["email"])} imArgs["email"]["immediate"] = `"not a bool"` - immdte := fmtTestConfigResource("view", "new", nilLst, viewDefaults, imArgs, nilLst) + immdte := fmtTestConfigResource("view", "new", globalPcArgs, viewDefaults, imArgs, nilLst) opArgs := map[string]map[string]string{"pagerduty": cloneDefaults(chnlDefaults["pagerduty"])} opArgs["pagerduty"]["operator"] = `1000` - opratr := fmtTestConfigResource("view", "new", nilLst, viewDefaults, opArgs, nilLst) + opratr := fmtTestConfigResource("view", "new", globalPcArgs, viewDefaults, opArgs, nilLst) trArgs := map[string]map[string]string{"webhook": cloneDefaults(chnlDefaults["webhook"])} trArgs["webhook"]["terminal"] = `"invalid"` - trmnal := fmtTestConfigResource("view", "new", nilLst, viewDefaults, trArgs, nilLst) + trmnal := fmtTestConfigResource("view", "new", globalPcArgs, viewDefaults, trArgs, nilLst) tiArgs := map[string]map[string]string{"email": cloneDefaults(chnlDefaults["email"])} tiArgs["email"]["triggerinterval"] = `18` - tintvl := fmtTestConfigResource("view", "new", nilLst, viewDefaults, tiArgs, nilLst) + tintvl := fmtTestConfigResource("view", "new", globalPcArgs, viewDefaults, tiArgs, nilLst) tlArgs := map[string]map[string]string{"slack": cloneDefaults(chnlDefaults["slack"])} tlArgs["slack"]["triggerlimit"] = `0` - tlimit := fmtTestConfigResource("view", "new", nilLst, viewDefaults, tlArgs, nilLst) + tlimit := fmtTestConfigResource("view", "new", globalPcArgs, viewDefaults, tlArgs, nilLst) resource.Test(t, resource.TestCase{ Providers: testAccProviders, @@ -134,11 +133,11 @@ func TestView_ErrorsChannel(t *testing.T) { func TestView_ErrorsEmailChannel(t *testing.T) { msArgs := map[string]map[string]string{"email": cloneDefaults(chnlDefaults["email"])} msArgs["email"]["emails"] = "" - misngE := fmtTestConfigResource("view", "new", nilLst, viewDefaults, msArgs, nilLst) + misngE := fmtTestConfigResource("view", "new", globalPcArgs, viewDefaults, msArgs, nilLst) inArgs := map[string]map[string]string{"email": cloneDefaults(chnlDefaults["email"])} inArgs["email"]["emails"] = `"not an array of strings"` - invldE := fmtTestConfigResource("view", "new", nilLst, viewDefaults, inArgs, nilLst) + invldE := fmtTestConfigResource("view", "new", globalPcArgs, viewDefaults, inArgs, nilLst) resource.Test(t, resource.TestCase{ Providers: testAccProviders, @@ -163,7 +162,7 @@ func TestView_ErrorsPagerDutyChannel(t *testing.T) { Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: fmtTestConfigResource("view", "new", nilLst, viewDefaults, chArgs, nilLst), + Config: fmtTestConfigResource("view", "new", globalPcArgs, viewDefaults, chArgs, nilLst), ExpectError: regexp.MustCompile("The argument \"key\" is required, but no definition was found."), }, }, @@ -173,11 +172,11 @@ func TestView_ErrorsPagerDutyChannel(t *testing.T) { func TestView_ErrorsSlackChannel(t *testing.T) { ulInvd := map[string]map[string]string{"slack": cloneDefaults(chnlDefaults["slack"])} ulInvd["slack"]["url"] = `"this is not a valid url"` - ulCfgE := fmtTestConfigResource("view", "new", nilLst, viewDefaults, ulInvd, nilLst) + ulCfgE := fmtTestConfigResource("view", "new", globalPcArgs, viewDefaults, ulInvd, nilLst) ulMsng := map[string]map[string]string{"slack": cloneDefaults(chnlDefaults["slack"])} ulMsng["slack"]["url"] = "" - ulCfgM := fmtTestConfigResource("view", "new", nilLst, viewDefaults, ulMsng, nilLst) + ulCfgM := fmtTestConfigResource("view", "new", globalPcArgs, viewDefaults, ulMsng, nilLst) resource.Test(t, resource.TestCase{ Providers: testAccProviders, @@ -197,23 +196,23 @@ func TestView_ErrorsSlackChannel(t *testing.T) { func TestView_ErrorsWebhookChannel(t *testing.T) { btArgs := map[string]map[string]string{"webhook": cloneDefaults(chnlDefaults["webhook"])} btArgs["webhook"]["bodytemplate"] = `"{\"test\": }"` - btCfgE := fmtTestConfigResource("view", "new", nilLst, viewDefaults, btArgs, nilLst) + btCfgE := fmtTestConfigResource("view", "new", globalPcArgs, viewDefaults, btArgs, nilLst) hdArgs := map[string]map[string]string{"webhook": cloneDefaults(chnlDefaults["webhook"])} hdArgs["webhook"]["headers"] = `["headers", "invalid", "array"]` - hdCfgE := fmtTestConfigResource("view", "new", nilLst, viewDefaults, hdArgs, nilLst) + hdCfgE := fmtTestConfigResource("view", "new", globalPcArgs, viewDefaults, hdArgs, nilLst) mdArgs := map[string]map[string]string{"webhook": cloneDefaults(chnlDefaults["webhook"])} mdArgs["webhook"]["method"] = `"false"` - mdCfgE := fmtTestConfigResource("view", "new", nilLst, viewDefaults, mdArgs, nilLst) + mdCfgE := fmtTestConfigResource("view", "new", globalPcArgs, viewDefaults, mdArgs, nilLst) ulInvd := map[string]map[string]string{"webhook": cloneDefaults(chnlDefaults["webhook"])} ulInvd["webhook"]["url"] = `"this is not a valid url"` - ulCfgE := fmtTestConfigResource("view", "new", nilLst, viewDefaults, ulInvd, nilLst) + ulCfgE := fmtTestConfigResource("view", "new", globalPcArgs, viewDefaults, ulInvd, nilLst) ulMsng := map[string]map[string]string{"webhook": cloneDefaults(chnlDefaults["webhook"])} ulMsng["webhook"]["url"] = "" - ulCfgM := fmtTestConfigResource("view", "new", nilLst, viewDefaults, ulMsng, nilLst) + ulCfgM := fmtTestConfigResource("view", "new", globalPcArgs, viewDefaults, ulMsng, nilLst) resource.Test(t, resource.TestCase{ Providers: testAccProviders, @@ -243,12 +242,12 @@ func TestView_ErrorsWebhookChannel(t *testing.T) { } func TestView_Basic(t *testing.T) { - iniCfg := fmtTestConfigResource("view", "new", nilLst, viewDefaults, nilOpt, nilLst) + iniCfg := fmtTestConfigResource("view", "new", globalPcArgs, viewDefaults, nilOpt, nilLst) rsArgs := cloneDefaults(rsDefaults["view"]) rsArgs["name"] = `"test2"` rsArgs["query"] = `"test2"` - updCfg := fmtTestConfigResource("view", "new", nilLst, rsArgs, nilOpt, nilLst) + updCfg := fmtTestConfigResource("view", "new", globalPcArgs, rsArgs, nilOpt, nilLst) resource.Test(t, resource.TestCase{ Providers: testAccProviders, @@ -256,7 +255,7 @@ func TestView_Basic(t *testing.T) { { Config: iniCfg, Check: resource.ComposeTestCheckFunc( - testViewExists("logdna_view.new"), + testResourceExists("view", "new"), resource.TestCheckResourceAttr("logdna_view.new", "name", "test"), resource.TestCheckResourceAttr("logdna_view.new", "query", "test"), ), @@ -264,7 +263,7 @@ func TestView_Basic(t *testing.T) { { Config: updCfg, Check: resource.ComposeTestCheckFunc( - testViewExists("logdna_view.new"), + testResourceExists("view", "new"), resource.TestCheckResourceAttr("logdna_view.new", "name", "test2"), resource.TestCheckResourceAttr("logdna_view.new", "query", "test2"), ), @@ -283,25 +282,25 @@ func TestView_BulkChannels(t *testing.T) { "email": cloneDefaults(chnlDefaults["email"]), "email1": cloneDefaults(chnlDefaults["email"]), } - emsCfg := fmtTestConfigResource("view", "new", nilLst, viewDefaults, emArgs, nilLst) + emsCfg := fmtTestConfigResource("view", "new", globalPcArgs, viewDefaults, emArgs, nilLst) pdArgs := map[string]map[string]string{ "pagerduty": cloneDefaults(chnlDefaults["pagerduty"]), "pagerduty1": cloneDefaults(chnlDefaults["pagerduty"]), } - pdsCfg := fmtTestConfigResource("view", "new", nilLst, viewDefaults, pdArgs, nilLst) + pdsCfg := fmtTestConfigResource("view", "new", globalPcArgs, viewDefaults, pdArgs, nilLst) slArgs := map[string]map[string]string{ "slack": cloneDefaults(chnlDefaults["slack"]), "slack1": cloneDefaults(chnlDefaults["slack"]), } - slsCfg := fmtTestConfigResource("view", "new", nilLst, viewDefaults, slArgs, nilLst) + slsCfg := fmtTestConfigResource("view", "new", globalPcArgs, viewDefaults, slArgs, nilLst) wbArgs := map[string]map[string]string{ "webhook": cloneDefaults(chnlDefaults["webhook"]), "webhook1": cloneDefaults(chnlDefaults["webhook"]), } - wbsCfg := fmtTestConfigResource("view", "new", nilLst, viewDefaults, wbArgs, nilLst) + wbsCfg := fmtTestConfigResource("view", "new", globalPcArgs, viewDefaults, wbArgs, nilLst) resource.Test(t, resource.TestCase{ Providers: testAccProviders, @@ -309,7 +308,7 @@ func TestView_BulkChannels(t *testing.T) { { Config: emsCfg, Check: resource.ComposeTestCheckFunc( - testViewExists("logdna_view.new"), + testResourceExists("view", "new"), resource.TestCheckResourceAttr("logdna_view.new", "name", "test"), resource.TestCheckResourceAttr("logdna_view.new", "query", "test"), resource.TestCheckResourceAttr("logdna_view.new", "email_channel.#", "2"), @@ -323,7 +322,7 @@ func TestView_BulkChannels(t *testing.T) { { Config: pdsCfg, Check: resource.ComposeTestCheckFunc( - testViewExists("logdna_view.new"), + testResourceExists("view", "new"), resource.TestCheckResourceAttr("logdna_view.new", "name", "test"), resource.TestCheckResourceAttr("logdna_view.new", "query", "test"), resource.TestCheckResourceAttr("logdna_view.new", "pagerduty_channel.#", "2"), @@ -337,7 +336,7 @@ func TestView_BulkChannels(t *testing.T) { { Config: slsCfg, Check: resource.ComposeTestCheckFunc( - testViewExists("logdna_view.new"), + testResourceExists("view", "new"), resource.TestCheckResourceAttr("logdna_view.new", "name", "test"), resource.TestCheckResourceAttr("logdna_view.new", "query", "test"), resource.TestCheckResourceAttr("logdna_view.new", "slack_channel.#", "2"), @@ -351,7 +350,7 @@ func TestView_BulkChannels(t *testing.T) { { Config: wbsCfg, Check: resource.ComposeTestCheckFunc( - testViewExists("logdna_view.new"), + testResourceExists("view", "new"), resource.TestCheckResourceAttr("logdna_view.new", "name", "test"), resource.TestCheckResourceAttr("logdna_view.new", "query", "test"), resource.TestCheckResourceAttr("logdna_view.new", "webhook_channel.#", "2"), @@ -393,7 +392,7 @@ func TestView_MultipleChannels(t *testing.T) { rsArgs["tags"] = `["tags1", "tags2"]` iniCfg := fmt.Sprintf( "%s\n%s\n%s", - fmtTestConfigResource("view", "new", nilLst, rsArgs, chArgs, dependencies), + fmtTestConfigResource("view", "new", globalPcArgs, rsArgs, chArgs, dependencies), fmtResourceBlock("category", "cat_1", cat1Args, nilOpt, nilLst), fmtResourceBlock("category", "cat_2", cat2Args, nilOpt, nilLst), ) @@ -408,7 +407,7 @@ func TestView_MultipleChannels(t *testing.T) { rsUptd["query"] = `"query2"` updCfg := fmt.Sprintf( "%s\n%s\n%s", - fmtTestConfigResource("view", "new", nilLst, rsUptd, chArgs, dependencies), + fmtTestConfigResource("view", "new", globalPcArgs, rsUptd, chArgs, dependencies), fmtResourceBlock("category", "cat_1", cat1Args, nilOpt, nilLst), fmtResourceBlock("category", "cat_2", cat2Args, nilOpt, nilLst), ) @@ -419,7 +418,7 @@ func TestView_MultipleChannels(t *testing.T) { { Config: iniCfg, Check: resource.ComposeTestCheckFunc( - testViewExists("logdna_view.new"), + testResourceExists("view", "new"), resource.TestCheckResourceAttr("logdna_view.new", "name", "test"), resource.TestCheckResourceAttr("logdna_view.new", "query", "test"), resource.TestCheckResourceAttr("logdna_view.new", "apps.#", "2"), @@ -481,7 +480,7 @@ func TestView_MultipleChannels(t *testing.T) { { Config: updCfg, Check: resource.ComposeTestCheckFunc( - testViewExists("logdna_view.new"), + testResourceExists("view", "new"), resource.TestCheckResourceAttr("logdna_view.new", "name", "test2"), resource.TestCheckResourceAttr("logdna_view.new", "query", "query2"), resource.TestCheckResourceAttr("logdna_view.new", "apps.0", "app3"), @@ -543,7 +542,7 @@ func TestView_PresetAlert(t *testing.T) { "%s\n%s\n%s", fmtResourceBlock("category", "test_category", catArgs, nilOpt, nilLst), fmtResourceBlock("alert", "test_preset_alert_ins", alertInsArgs, chArgs, nilLst), - fmtTestConfigResource("view", "test_view", nilLst, rsArgs, nilOpt, dependenciesIns), + fmtTestConfigResource("view", "test_view", globalPcArgs, rsArgs, nilOpt, dependenciesIns), ) rsUptd := cloneDefaults(rsDefaults["view"]) @@ -559,7 +558,7 @@ func TestView_PresetAlert(t *testing.T) { "%s\n%s\n%s", fmtResourceBlock("category", "test_category", catArgs, nilOpt, nilLst), fmtResourceBlock("alert", "test_preset_alert_upd", alertUpdArgs, chArgs, nilLst), - fmtTestConfigResource("view", "test_view", nilLst, rsUptd, nilOpt, dependenciesUpd), + fmtTestConfigResource("view", "test_view", globalPcArgs, rsUptd, nilOpt, dependenciesUpd), ) resource.Test(t, resource.TestCase{ @@ -568,7 +567,7 @@ func TestView_PresetAlert(t *testing.T) { { Config: iniCfg, Check: resource.ComposeTestCheckFunc( - testViewExists("logdna_view.test_view"), + testResourceExists("view", "test-view"), resource.TestCheckResourceAttr("logdna_view.test_view", "name", "test"), resource.TestCheckResourceAttr("logdna_view.test_view", "query", "test"), resource.TestCheckResourceAttr("logdna_view.test_view", "apps.#", "2"), @@ -596,7 +595,7 @@ func TestView_PresetAlert(t *testing.T) { { Config: updCfg, Check: resource.ComposeTestCheckFunc( - testViewExists("logdna_view.test_view"), + testResourceExists("view", "test-view"), resource.TestCheckResourceAttr("logdna_view.test_view", "name", "test2"), resource.TestCheckResourceAttr("logdna_view.test_view", "query", "query2"), resource.TestCheckResourceAttr("logdna_view.test_view", "apps.0", "app3"), @@ -641,7 +640,7 @@ func TestView_ErrorsConflictPresetId(t *testing.T) { rsArgs["tags"] = `["tags1", "tags2"]` rsArgs["presetid"] = `"1q2w3e4r5t"` - incCfg := fmtTestConfigResource("view", "test_view", nilLst, rsArgs, chArgs, nilLst) + incCfg := fmtTestConfigResource("view", "test_view", globalPcArgs, rsArgs, chArgs, nilLst) resource.Test(t, resource.TestCase{ Providers: testAccProviders, @@ -653,17 +652,3 @@ func TestView_ErrorsConflictPresetId(t *testing.T) { }, }) } - -func testViewExists(n string) resource.TestCheckFunc { - return func(s *terraform.State) error { - rs, ok := s.RootModule().Resources[n] - if rs.Primary.ID == "" { - return fmt.Errorf("No ID set") - } - if !ok { - return fmt.Errorf("Not found: %s", n) - } - - return nil - } -} diff --git a/logdna/response_types.go b/logdna/response_types.go index 26005ba..d39bd81 100644 --- a/logdna/response_types.go +++ b/logdna/response_types.go @@ -31,6 +31,13 @@ type alertResponse struct { PresetID string `json:"presetid"` } +type keyResponse struct { + KeyID string `json:"id"` + Key string `json:"key"` + Type string `json:"type"` + Created int `json:"created,omitempty"` +} + // channelResponse contains channel data returned from the logdna APIs // NOTE - Properties with `interface` are due to the APIs returning // some things as strings (PUT/emails) and other times arrays (GET/emails)