diff --git a/GNUmakefile b/GNUmakefile index 920c116..4f6e645 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -33,11 +33,9 @@ dev: cd local && TF_LOG=TRACE terraform init -upgrade fmt: - go fmt ./checkly - terraform fmt - -doc: - ./tools/tfplugindocs + go fmt ./... + terraform fmt -recursive +# Generate docs generate: - go generate ./... + cd tools; go generate ./... diff --git a/checkly/data_source_static_ips.go b/checkly/data_source_static_ips.go deleted file mode 100644 index c5cbaa5..0000000 --- a/checkly/data_source_static_ips.go +++ /dev/null @@ -1,109 +0,0 @@ -package checkly - -import ( - "context" - "fmt" - "slices" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - checkly "github.com/checkly/checkly-go-sdk" -) - -func dataSourceStaticIPs() *schema.Resource { - return &schema.Resource{ - Read: dataSourceStaticIPsRead, - Schema: map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Computed: true, - Description: "ID of the static IPs data source.", - }, - "addresses": { - Type: schema.TypeSet, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - Computed: true, - Description: "Static IP addresses for Checkly's runner infrastructure.", - }, - "locations": { - Type: schema.TypeSet, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - Optional: true, - Description: "Specify the locations you want to get static IPs for.", - }, - "ip_family": { - Type: schema.TypeString, - Optional: true, - Description: "Specify the IP families you want to get static IPs for. Only `IPv6` or `IPv4` are valid options.", - ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) { - value := val.(string) - if !slices.Contains([]string{"IPv6", "IPv4"}, value) { - errs = append(errs, fmt.Errorf("%q must be either \"IPv6\" or \"IPv4\"", key)) - } - return - }, - }, - }, - } -} - -func dataSourceStaticIPsRead(d *schema.ResourceData, client interface{}) error { - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - staticIPs, err := client.(checkly.Client).GetStaticIPs(ctx) - defer cancel() - if err != nil { - return fmt.Errorf("dateSourceStaticIPsRead: API error: %w", err) - } - return dataSourceFromStaticIPs(staticIPs, d) -} - -func dataSourceFromStaticIPs(s []checkly.StaticIP, d *schema.ResourceData) error { - var staticIPs []checkly.StaticIP - var addresses []string - - locations := stringsFromSet(d.Get("locations").(*schema.Set)) - ip_family := d.Get("ip_family").(string) - - // only locations is set for filtering - if len(locations) > 0 && ip_family == "" { - for _, ip := range s { - if slices.Contains(locations, ip.Region) { - staticIPs = append(staticIPs, ip) - } - } - // only ip_family is set for filtering - } else if ip_family != "" && len(locations) == 0 { - for _, ip := range s { - if ip_family == "IPv4" && ip.Address.Addr().Is4() { - staticIPs = append(staticIPs, ip) - } else if ip_family == "IPv6" && ip.Address.Addr().Is6() { - staticIPs = append(staticIPs, ip) - } - } - // both region and ip_family are set for filtering - } else if len(locations) > 0 && ip_family != "" { - for _, ip := range s { - if ip_family == "IPv4" && ip.Address.Addr().Is4() && slices.Contains(locations, ip.Region) { - staticIPs = append(staticIPs, ip) - } else if ip_family == "IPv6" && ip.Address.Addr().Is6() && slices.Contains(locations, ip.Region) { - staticIPs = append(staticIPs, ip) - } - } - // no region nor ip_family filters set - } else { - staticIPs = s - } - - for _, ip := range staticIPs { - addresses = append(addresses, ip.Address.String()) - } - - d.Set("addresses", addresses) - d.SetId("checkly_static_ips_data_source_id") - - return nil -} diff --git a/checkly/data_source_static_ips_test.go b/checkly/data_source_static_ips_test.go deleted file mode 100644 index 0ba4bf4..0000000 --- a/checkly/data_source_static_ips_test.go +++ /dev/null @@ -1,135 +0,0 @@ -package checkly - -import ( - "regexp" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccStaticIPsAll(t *testing.T) { - config := `data "checkly_static_ips" "test" {}` - - accTestCase(t, []resource.TestStep{ - { - Config: config, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "data.checkly_static_ips.test", - "addresses.#", - "162", - ), - ), - }, - }) -} - -func TestAccStaticIPsTwoRegionsOnly(t *testing.T) { - config := `data "checkly_static_ips" "test" { - locations = ["us-east-1","ap-southeast-1"] - }` - - accTestCase(t, []resource.TestStep{ - { - Config: config, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "data.checkly_static_ips.test", - "addresses.#", - "20", - ), - ), - }, - }) -} - -func TestAccStaticIPsIPv6Only(t *testing.T) { - config := `data "checkly_static_ips" "test" { - ip_family = "IPv6" - }` - - accTestCase(t, []resource.TestStep{ - { - Config: config, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "data.checkly_static_ips.test", - "addresses.#", - "22", - ), - ), - }, - }) -} - -func TestAccStaticIPsIPv4Only(t *testing.T) { - config := `data "checkly_static_ips" "test" { - ip_family = "IPv4" - }` - - accTestCase(t, []resource.TestStep{ - { - Config: config, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "data.checkly_static_ips.test", - "addresses.#", - "140", - ), - ), - }, - }) -} - -func TestAccStaticIPsIPv6AndOneRegionOnly(t *testing.T) { - config := `data "checkly_static_ips" "test" { - ip_family = "IPv6" - locations = ["us-east-1"] - }` - - accTestCase(t, []resource.TestStep{ - { - Config: config, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "data.checkly_static_ips.test", - "addresses.#", - "1", - ), - ), - }, - }) -} - -func TestAccStaticIPsIPv4AndOneRegionOnly(t *testing.T) { - config := `data "checkly_static_ips" "test" { - ip_family = "IPv4" - locations = ["us-east-1"] - }` - - accTestCase(t, []resource.TestStep{ - { - Config: config, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "data.checkly_static_ips.test", - "addresses.#", - "12", - ), - ), - }, - }) -} - -func TestAccStaticIPsInvalidIPFamily(t *testing.T) { - config := `data "checkly_static_ips" "test" { - ip_family = "invalid" - }` - - accTestCase(t, []resource.TestStep{ - { - Config: config, - ExpectError: regexp.MustCompile(`"ip_family" must be either "IPv6" or "IPv4"`), - }, - }) -} diff --git a/checkly/error_with_log.go b/checkly/error_with_log.go deleted file mode 100644 index 25acb78..0000000 --- a/checkly/error_with_log.go +++ /dev/null @@ -1,24 +0,0 @@ -package checkly - -import ( - "encoding/json" - "fmt" -) - -// ErrorLog defines ErrorLog type -type ErrorLog map[string]interface{} - -// ErrorWithLog defines checkly error type -type ErrorWithLog struct { - Err string - Data *ErrorLog -} - -func (e ErrorWithLog) Error() string { - data, _ := json.Marshal(e.Data) - return fmt.Sprintf("%s [%s]", e.Err, data) -} - -func makeError(err string, l *ErrorLog) ErrorWithLog { - return ErrorWithLog{err, l} -} diff --git a/checkly/helpers.go b/checkly/helpers.go deleted file mode 100644 index a9233e4..0000000 --- a/checkly/helpers.go +++ /dev/null @@ -1,20 +0,0 @@ -package checkly - -import ( - "os" - "strconv" - "time" -) - -func apiCallTimeout() time.Duration { - timeout := os.Getenv("API_CALL_TIMEOUT") - if timeout != "" { - v, err := strconv.ParseInt(timeout, 10, 64) - if err != nil || v < 1 { - panic("Invalid API_CALL_TIMEOUT value, must be a positive number") - } else { - return time.Duration(v) * time.Second - } - } - return 15 * time.Second -} diff --git a/checkly/integration_test.go b/checkly/integration_test.go deleted file mode 100644 index fae3f59..0000000 --- a/checkly/integration_test.go +++ /dev/null @@ -1,50 +0,0 @@ -//go:build integration -// +build integration - -package checkly - -import ( - "os" - "testing" - - "github.com/gruntwork-io/terratest/modules/terraform" -) - -func getAPIKey(t *testing.T) string { - key := os.Getenv("CHECKLY_API_KEY") - if key == "" { - t.Fatal("'CHECKLY_API_KEY' must be set for integration tests") - } - - return key -} - -func getAccountId(t *testing.T) string { - key := os.Getenv("CHECKLY_ACCOUNT_ID") - if key == "" { - t.Fatal("'CHECKLY_ACCOUNT_ID' must be set for integration tests") - } - return key -} - -func TestChecklyTerraformIntegration(t *testing.T) { - t.Parallel() - terraformOptions := &terraform.Options{ - TerraformDir: "../", - Vars: map[string]interface{}{ - "checkly_api_key": getAPIKey(t), - "checkly_account_id": getAccountId(t), - }, - } - defer terraform.Destroy(t, terraformOptions) - terraform.InitAndApply(t, terraformOptions) - planPath := "./test.plan" - exit, err := terraform.GetExitCodeForTerraformCommandE(t, terraformOptions, terraform.FormatArgs(terraformOptions, "plan", "--out="+planPath, "-input=false", "-lock=true", "-detailed-exitcode")...) - if err != nil { - t.Fatal(err) - } - defer os.Remove(planPath) - if exit != terraform.DefaultSuccessExitCode { - t.Fatalf("want DefaultSuccessExitCode, got %d", exit) - } -} diff --git a/checkly/provider.go b/checkly/provider.go deleted file mode 100644 index 797126b..0000000 --- a/checkly/provider.go +++ /dev/null @@ -1,102 +0,0 @@ -package checkly - -import ( - "fmt" - "io" - "os" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/checkly/checkly-go-sdk" -) - -// Provider makes the provider available to Terraform. -func Provider() *schema.Provider { - return &schema.Provider{ - Schema: map[string]*schema.Schema{ - "api_key": { - Type: schema.TypeString, - Required: true, - DefaultFunc: schema.EnvDefaultFunc("CHECKLY_API_KEY", nil), - }, - "api_url": { - Type: schema.TypeString, - Optional: true, - DefaultFunc: schema.EnvDefaultFunc("CHECKLY_API_URL", nil), - }, - "account_id": { - Type: schema.TypeString, - Optional: true, - DefaultFunc: schema.EnvDefaultFunc("CHECKLY_ACCOUNT_ID", nil), - }, - }, - ResourcesMap: map[string]*schema.Resource{ - "checkly_check": resourceCheck(), - "checkly_heartbeat": resourceHeartbeat(), - "checkly_check_group": resourceCheckGroup(), - "checkly_snippet": resourceSnippet(), - "checkly_dashboard": resourceDashboard(), - "checkly_maintenance_windows": resourceMaintenanceWindow(), - "checkly_alert_channel": resourceAlertChannel(), - "checkly_trigger_check": resourceTriggerCheck(), - "checkly_trigger_group": resourceTriggerGroup(), - "checkly_environment_variable": resourceEnvironmentVariable(), - "checkly_private_location": resourcePrivateLocation(), - }, - DataSourcesMap: map[string]*schema.Resource{ - "checkly_static_ips": dataSourceStaticIPs(), - }, - ConfigureFunc: func(r *schema.ResourceData) (interface{}, error) { - debugLog := os.Getenv("CHECKLY_DEBUG_LOG") - var debugOutput io.Writer - if debugLog != "" { - debugFile, err := os.OpenFile(debugLog, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600) - if err != nil { - panic(fmt.Sprintf("can't write to debug log file: %v", err)) - } - debugOutput = debugFile - } - - apiKey := "" - switch v := r.Get("api_key").(type) { - case string: - apiKey = v - } - - apiUrl := "" - switch v := r.Get("api_url").(type) { - case string: - apiUrl = v - } - - if apiUrl == "" { - apiUrl = "https://api.checklyhq.com" - } - - client := checkly.NewClient( - apiUrl, - apiKey, - nil, - debugOutput, - ) - - accountId := "" - switch v := r.Get("account_id").(type) { - case string: - accountId = v - } - if accountId != "" { - client.SetAccountId(accountId) - } - - checklyApiSource := os.Getenv("CHECKLY_API_SOURCE") - if checklyApiSource != "" { - client.SetChecklySource(checklyApiSource) - } else { - client.SetChecklySource("TF") - } - - return client, nil - }, - } -} diff --git a/checkly/provider_test.go b/checkly/provider_test.go deleted file mode 100644 index 4704aa9..0000000 --- a/checkly/provider_test.go +++ /dev/null @@ -1,11 +0,0 @@ -package checkly - -import ( - "testing" -) - -func TestProvider(t *testing.T) { - if err := Provider().InternalValidate(); err != nil { - t.Fatalf("err: %s", err) - } -} diff --git a/checkly/resource_alert_channel.go b/checkly/resource_alert_channel.go deleted file mode 100644 index ebcfdec..0000000 --- a/checkly/resource_alert_channel.go +++ /dev/null @@ -1,572 +0,0 @@ -package checkly - -import ( - "context" - "encoding/json" - "fmt" - "strings" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/checkly/checkly-go-sdk" -) - -const ( - AcFieldEmail = "email" - AcFieldEmailAddress = "address" - AcFieldSlack = "slack" - AcFieldSlackURL = "url" - AcFieldSlackChannel = "channel" - AcFieldSMS = "sms" - AcFieldSMSName = "name" - AcFieldSMSNumber = "number" - AcFieldWebhook = "webhook" - AcFieldWebhookName = "name" - AcFieldWebhookMethod = "method" - AcFieldWebhookHeaders = "headers" - AcFieldWebhookQueryParams = "query_parameters" - AcFieldWebhookTemplate = "template" - AcFieldWebhookURL = "url" - AcFieldWebhookSecret = "webhook_secret" - AcFieldWebhookType = "webhook_type" - AcFieldOpsgenie = "opsgenie" - AcFieldOpsgenieName = "name" - AcFieldOpsgenieAPIKey = "api_key" - AcFieldOpsgenieRegion = "region" - AcFieldOpsgeniePriority = "priority" - AcFieldPagerduty = "pagerduty" - AcFieldPagerdutyAccount = "account" - AcFieldPagerdutyServiceKey = "service_key" - AcFieldPagerdutyServiceName = "service_name" - AcFieldSendRecovery = "send_recovery" - AcFieldSendFailure = "send_failure" - AcFieldSendDegraded = "send_degraded" - AcFieldSSLExpiry = "ssl_expiry" - AcFieldSSLExpiryThreshold = "ssl_expiry_threshold" - AcFieldCall = "call" - AcFieldCallName = "name" - AcFieldCallNumber = "number" -) - -func resourceAlertChannel() *schema.Resource { - return &schema.Resource{ - Description: "Allows you to define alerting channels for the checks and groups in your account", - Create: resourceAlertChannelCreate, - Read: resourceAlertChannelRead, - Update: resourceAlertChannelUpdate, - Delete: resourceAlertChannelDelete, - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, - }, - Schema: map[string]*schema.Schema{ - AcFieldEmail: { - Type: schema.TypeSet, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - AcFieldEmailAddress: { - Type: schema.TypeString, - Required: true, - Description: "The email address of this email alert channel.", - }, - }, - }, - }, - AcFieldSlack: { - Type: schema.TypeSet, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - AcFieldSlackURL: { - Type: schema.TypeString, - Required: true, - Description: "The Slack webhook URL", - }, - AcFieldSlackChannel: { - Type: schema.TypeString, - Required: true, - Description: "The name of the alert's Slack channel", - }, - }, - }, - }, - AcFieldSMS: { - Type: schema.TypeSet, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - AcFieldSMSName: { - Type: schema.TypeString, - Required: true, - Description: "The name of this alert channel", - }, - AcFieldSMSNumber: { - Type: schema.TypeString, - Required: true, - Description: "The mobile number to receive the alerts", - }, - }, - }, - }, - AcFieldCall: { - Type: schema.TypeSet, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - AcFieldCallName: { - Type: schema.TypeString, - Required: true, - Description: "The name of this alert channel", - }, - AcFieldCallNumber: { - Type: schema.TypeString, - Required: true, - Description: "The mobile number to receive the alerts", - }, - }, - }, - }, - AcFieldWebhook: { - Type: schema.TypeSet, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - AcFieldWebhookName: { - Type: schema.TypeString, - Required: true, - }, - AcFieldWebhookMethod: { - Type: schema.TypeString, - Optional: true, - Default: "POST", - Description: "(Default `POST`)", - }, - AcFieldWebhookHeaders: { - Type: schema.TypeMap, - Optional: true, - Computed: true, - DefaultFunc: func() (interface{}, error) { - return []tfMap{}, nil - }, - }, - AcFieldWebhookQueryParams: { - Type: schema.TypeMap, - Optional: true, - Computed: true, - DefaultFunc: func() (interface{}, error) { - return []tfMap{}, nil - }, - }, - AcFieldWebhookTemplate: { - Type: schema.TypeString, - Optional: true, - }, - AcFieldWebhookURL: { - Type: schema.TypeString, - Required: true, - }, - AcFieldWebhookSecret: { - Type: schema.TypeString, - Optional: true, - }, - AcFieldWebhookType: { - Type: schema.TypeString, - Optional: true, - Description: "Type of the webhook. Possible values are 'WEBHOOK_DISCORD', 'WEBHOOK_FIREHYDRANT', 'WEBHOOK_GITLAB_ALERT', 'WEBHOOK_SPIKESH', 'WEBHOOK_SPLUNK', 'WEBHOOK_MSTEAMS' and 'WEBHOOK_TELEGRAM'.", - ValidateFunc: func(value interface{}, key string) (warns []string, errs []error) { - v := value.(string) - isValid := false - options := []string{"WEBHOOK_DISCORD", "WEBHOOK_FIREHYDRANT", "WEBHOOK_GITLAB_ALERT", "WEBHOOK_SPIKESH", "WEBHOOK_SPLUNK", "WEBHOOK_MSTEAMS", "WEBHOOK_TELEGRAM"} - for _, option := range options { - if v == option { - isValid = true - } - } - if !isValid { - errs = append(errs, fmt.Errorf("%q must be one of %v, got %s", key, options, v)) - } - return warns, errs - }, - }, - }, - }, - }, - AcFieldOpsgenie: { - Type: schema.TypeSet, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - AcFieldOpsgenieName: { - Type: schema.TypeString, - Required: true, - }, - AcFieldOpsgenieAPIKey: { - Type: schema.TypeString, - Required: true, - }, - AcFieldOpsgenieRegion: { - Type: schema.TypeString, - Required: true, - }, - AcFieldOpsgeniePriority: { - Type: schema.TypeString, - Required: true, - }, - }, - }, - }, - AcFieldPagerduty: { - Type: schema.TypeSet, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - AcFieldPagerdutyServiceKey: { - Type: schema.TypeString, - Required: true, - }, - AcFieldPagerdutyServiceName: { - Type: schema.TypeString, - Optional: true, - }, - AcFieldPagerdutyAccount: { - Type: schema.TypeString, - Optional: true, - }, - }, - }, - }, - AcFieldSendRecovery: { - Type: schema.TypeBool, - Optional: true, - Default: true, - Description: "(Default `true`)", - }, - AcFieldSendFailure: { - Type: schema.TypeBool, - Optional: true, - Default: true, - Description: "(Default `true`)", - }, - AcFieldSendDegraded: { - Type: schema.TypeBool, - Optional: true, - Default: false, - Description: "(Default `false`)", - }, - AcFieldSSLExpiry: { - Type: schema.TypeBool, - Optional: true, - Default: false, - Description: "(Default `false`)", - }, - AcFieldSSLExpiryThreshold: { - Type: schema.TypeInt, - Optional: true, - Default: 30, - ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) { - min := 1 - max := 30 - v := val.(int) - if v < min || v > max { - errs = append(errs, fmt.Errorf("%q must be between %d and %d, got: %d", key, min, max, v)) - } - return warns, errs - }, - Description: "Value must be between 1 and 30 (Default `30`)", - }, - }, - } -} - -func resourceAlertChannelCreate(d *schema.ResourceData, client interface{}) error { - ac, err := alertChannelFromResourceData(d) - if err != nil { - return makeError("resourceAlertChannelCreate.1", &ErrorLog{"err": err.Error()}) - } - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - resp, err := client.(checkly.Client).CreateAlertChannel(ctx, ac) - if err != nil { - cjson, _ := json.Marshal(ac.GetConfig()) - return makeError("resourceAlertChannelCreate.2", &ErrorLog{ - "err": err.Error(), - "type": ac.Type, - "config": string(cjson), - }) - } - d.SetId(fmt.Sprintf("%d", resp.ID)) - return resourceAlertChannelRead(d, client) -} - -func resourceAlertChannelRead(d *schema.ResourceData, client interface{}) error { - ID, err := resourceIDToInt(d.Id()) - if err != nil { - return makeError("resourceAlertChannelRead.1", &ErrorLog{"err": err.Error()}) - } - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - ac, err := client.(checkly.Client).GetAlertChannel(ctx, ID) - if err != nil { - if strings.Contains(err.Error(), "404") { - //if resource is deleted remotely, then mark it as - //successfully gone by unsetting it's ID - d.SetId("") - return nil - } - return makeError("resourceAlertChannelRead.2", &ErrorLog{"err": err.Error()}) - } - return resourceDataFromAlertChannel(ac, d) -} - -func resourceAlertChannelUpdate(d *schema.ResourceData, client interface{}) error { - ac, err := alertChannelFromResourceData(d) - if err != nil { - return makeError("resourceAlertChannelUpdate.1", &ErrorLog{"err": err.Error()}) - } - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - _, err = client.(checkly.Client).UpdateAlertChannel(ctx, ac.ID, ac) - if err != nil { - return makeError("resourceAlertChannelUpdate.2", &ErrorLog{"err": err.Error()}) - } - d.SetId(fmt.Sprintf("%d", ac.ID)) - return resourceAlertChannelRead(d, client) -} - -func resourceAlertChannelDelete(d *schema.ResourceData, client interface{}) error { - ID, err := resourceIDToInt(d.Id()) - if err != nil { - return makeError("resourceAlertChannelDelete.1", &ErrorLog{"err": err.Error()}) - } - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - if err := client.(checkly.Client).DeleteAlertChannel(ctx, ID); err != nil { - return makeError("resourceAlertChannelDelete.2", &ErrorLog{"err": err.Error()}) - } - return nil -} - -func resourceDataFromAlertChannel(it *checkly.AlertChannel, d *schema.ResourceData) error { - d.Set(AcFieldEmail, setFromEmail(it.Email)) - d.Set(AcFieldSMS, setFromSMS(it.SMS)) - d.Set(AcFieldCall, setFromCall(it.CALL)) - d.Set(AcFieldSlack, setFromSlack(it.Slack)) - d.Set(AcFieldWebhook, setFromWebhook(it.Webhook)) - d.Set(AcFieldOpsgenie, setFromOpsgenie(it.Opsgenie)) - d.Set(AcFieldPagerduty, setFromPagerduty(it.Pagerduty)) - if it.SendRecovery != nil { - d.Set(AcFieldSendRecovery, *it.SendRecovery) - } - if it.SendFailure != nil { - d.Set(AcFieldSendFailure, *it.SendFailure) - } - if it.SendDegraded != nil { - d.Set(AcFieldSendDegraded, *it.SendDegraded) - } - if it.SSLExpiry != nil { - d.Set(AcFieldSSLExpiry, *it.SSLExpiry) - } - if it.SSLExpiryThreshold != nil { - d.Set(AcFieldSSLExpiryThreshold, *it.SSLExpiryThreshold) - } - return nil -} - -func alertChannelFromResourceData(d *schema.ResourceData) (checkly.AlertChannel, error) { - ac := checkly.AlertChannel{} - ID, err := resourceIDToInt(d.Id()) - if err != nil { - return ac, makeError("alertChannelFromResourceData.1", &ErrorLog{"err": err.Error()}) - } - if err == nil { - ac.ID = ID - } - - sendRecovery := d.Get(AcFieldSendRecovery).(bool) - ac.SendRecovery = &sendRecovery - - sendFailure := d.Get(AcFieldSendFailure).(bool) - ac.SendFailure = &sendFailure - - sndDegraded := d.Get(AcFieldSendDegraded).(bool) - ac.SendDegraded = &sndDegraded - - sslExpiry := d.Get(AcFieldSSLExpiry).(bool) - ac.SSLExpiry = &sslExpiry - - if v, ok := d.GetOk(AcFieldSSLExpiryThreshold); ok { - i := v.(int) - ac.SSLExpiryThreshold = &i - } - - fields := []string{AcFieldEmail, AcFieldSMS, AcFieldCall, AcFieldSlack, AcFieldWebhook, AcFieldOpsgenie, AcFieldPagerduty} - setCount := 0 - for _, field := range fields { - cfgSet := (d.Get(field)).(*schema.Set) - if cfgSet.Len() > 0 { - ac.Type = strings.ToUpper(field) - c, err := alertChannelConfigFromSet(ac.Type, cfgSet) - if err != nil { - return ac, makeError("alertChannelFromResourceData.2", &ErrorLog{"err": err.Error()}) - } - ac.SetConfig(c) - setCount++ - } - } - if setCount > 1 { - return ac, makeError("Alert-Channel config can't contain more than one Channel", nil) - } - return ac, nil -} - -func alertChannelConfigFromSet(channelType string, s *schema.Set) (interface{}, error) { - if s.Len() == 0 { - return nil, nil - } - cfg := s.List()[0].(map[string]interface{}) - switch channelType { - case checkly.AlertTypeEmail: - return &checkly.AlertChannelEmail{ - Address: cfg[AcFieldEmailAddress].(string), - }, nil - case checkly.AlertTypeSMS: - return &checkly.AlertChannelSMS{ - Name: cfg[AcFieldSMSName].(string), - Number: cfg[AcFieldSMSNumber].(string), - }, nil - case checkly.AlertTypeCall: - return &checkly.AlertChannelCall{ - Name: cfg[AcFieldCallName].(string), - Number: cfg[AcFieldCallNumber].(string), - }, nil - case checkly.AlertTypeSlack: - return &checkly.AlertChannelSlack{ - Channel: cfg[AcFieldSlackChannel].(string), - WebhookURL: cfg[AcFieldSlackURL].(string), - }, nil - case checkly.AlertTypeOpsgenie: - return &checkly.AlertChannelOpsgenie{ - Name: cfg[AcFieldOpsgenieName].(string), - APIKey: cfg[AcFieldOpsgenieAPIKey].(string), - Region: cfg[AcFieldOpsgenieRegion].(string), - Priority: cfg[AcFieldOpsgeniePriority].(string), - }, nil - case checkly.AlertTypePagerduty: - return &checkly.AlertChannelPagerduty{ - Account: cfg[AcFieldPagerdutyAccount].(string), - ServiceKey: cfg[AcFieldPagerdutyServiceKey].(string), - ServiceName: cfg[AcFieldPagerdutyServiceName].(string), - }, nil - case checkly.AlertTypeWebhook: - return &checkly.AlertChannelWebhook{ - Name: cfg[AcFieldWebhookName].(string), - Method: cfg[AcFieldWebhookMethod].(string), - Template: cfg[AcFieldWebhookTemplate].(string), - URL: cfg[AcFieldWebhookURL].(string), - WebhookSecret: cfg[AcFieldWebhookSecret].(string), - WebhookType: cfg[AcFieldWebhookType].(string), - Headers: keyValuesFromMap(cfg[AcFieldWebhookHeaders].(tfMap)), - QueryParameters: keyValuesFromMap(cfg[AcFieldWebhookQueryParams].(tfMap)), - }, nil - } - return nil, makeError("alertChannelConfigFromSet:unkownType", nil) -} - -func setFromEmail(cfg *checkly.AlertChannelEmail) []tfMap { - if cfg == nil { - return []tfMap{} - } - return []tfMap{ - { - AcFieldEmailAddress: cfg.Address, - }, - } -} - -func setFromSMS(cfg *checkly.AlertChannelSMS) []tfMap { - if cfg == nil { - return []tfMap{} - } - return []tfMap{ - { - AcFieldSMSName: cfg.Name, - AcFieldSMSNumber: cfg.Number, - }, - } -} - -func setFromCall(cfg *checkly.AlertChannelCall) []tfMap { - if cfg == nil { - return []tfMap{} - } - return []tfMap{ - { - AcFieldCallName: cfg.Name, - AcFieldCallNumber: cfg.Number, - }, - } -} - -func setFromSlack(cfg *checkly.AlertChannelSlack) []tfMap { - if cfg == nil { - return []tfMap{} - } - return []tfMap{ - { - AcFieldSlackChannel: cfg.Channel, - AcFieldSlackURL: cfg.WebhookURL, - }, - } -} - -func setFromWebhook(cfg *checkly.AlertChannelWebhook) []tfMap { - if cfg == nil { - return []tfMap{} - } - return []tfMap{ - { - AcFieldWebhookName: cfg.Name, - AcFieldWebhookMethod: cfg.Method, - AcFieldWebhookHeaders: mapFromKeyValues(cfg.Headers), - AcFieldWebhookQueryParams: mapFromKeyValues(cfg.QueryParameters), - AcFieldWebhookTemplate: cfg.Template, - AcFieldWebhookURL: cfg.URL, - AcFieldWebhookSecret: cfg.WebhookSecret, - AcFieldWebhookType: cfg.WebhookType, - }, - } -} - -func setFromOpsgenie(cfg *checkly.AlertChannelOpsgenie) []tfMap { - if cfg == nil { - return []tfMap{} - } - return []tfMap{ - { - AcFieldOpsgenieName: cfg.Name, - AcFieldOpsgenieAPIKey: cfg.APIKey, - AcFieldOpsgenieRegion: cfg.Region, - AcFieldOpsgeniePriority: cfg.Priority, - }, - } -} - -func setFromPagerduty(cfg *checkly.AlertChannelPagerduty) []tfMap { - if cfg == nil { - return []tfMap{} - } - return []tfMap{ - { - AcFieldPagerdutyAccount: cfg.Account, - AcFieldPagerdutyServiceKey: cfg.ServiceKey, - AcFieldPagerdutyServiceName: cfg.ServiceName, - }, - } -} diff --git a/checkly/resource_alert_channel_test.go b/checkly/resource_alert_channel_test.go deleted file mode 100644 index 884c0c0..0000000 --- a/checkly/resource_alert_channel_test.go +++ /dev/null @@ -1,202 +0,0 @@ -package checkly - -import ( - "fmt" - "regexp" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccEmail(t *testing.T) { - t.Parallel() - accTestCase(t, []resource.TestStep{ - { - Config: `resource "checkly_alert_channel" "t1" { - email { - address = "info@example.com" - } - send_recovery = false - send_failure = false - send_degraded = false - ssl_expiry = false - ssl_expiry_threshold = 10 - }`, - }, - }) -} - -func TestAccSlack(t *testing.T) { - t.Parallel() - accTestCase(t, []resource.TestStep{ - { - Config: `resource "checkly_alert_channel" "slack_ac" { - slack { - channel = "checkly_alerts" - url = "https://hooks.slack.com/services/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" - } - send_recovery = true - send_failure = true - send_degraded = false - ssl_expiry = true - ssl_expiry_threshold = 11 - }`, - }, - }) -} - -func TestAccSMS(t *testing.T) { - t.Parallel() - accTestCase(t, []resource.TestStep{ - { - Config: `resource "checkly_alert_channel" "sms_ac" { - sms { - name = "smsalerts" - number = "4917512345678" - } - }`, - }, - }) -} - -func TestAccOpsgenie(t *testing.T) { - t.Parallel() - accTestCase(t, []resource.TestStep{ - { - Config: `resource "checkly_alert_channel" "opsgenie_ac" { - opsgenie { - name = "opsalert" - api_key = "key1" - region = "EU" - priority = "P1" - } - }`, - }, - }) -} - -func TestAccPagerduty(t *testing.T) { - t.Parallel() - accTestCase(t, []resource.TestStep{ - { - Config: `resource "checkly_alert_channel" "pagerduty_ac" { - pagerduty { - account = "checkly" - service_key = "key1" - service_name = "pdalert" - } - }`, - }, - }) -} - -func TestAccWebhook(t *testing.T) { - t.Parallel() - accTestCase(t, []resource.TestStep{ - { - Config: `resource "checkly_alert_channel" "webhook_ac" { - webhook { - name = "webhhookalerts" - method = "get" - headers = { - X-HEADER-1 = "foo" - } - query_parameters = { - query1 = "bar" - } - template = "tmpl" - url = "https://example.com/webhook" - webhook_secret = "foo-secret" - } - }`, - }, - }) -} - -func TestAccFail(t *testing.T) { - t.Parallel() - cases := []struct { - Config string - Error string - }{ - { - Config: `resource "checkly_alert_channel" "t1" { - email { } - }`, - Error: `The argument "address" is required`, - }, - { - Config: `resource "checkly_alert_channel" "t1" { - sms { - } - }`, - Error: `The argument "number" is required`, - }, - { - Config: `resource "checkly_alert_channel" "t1" { - slack { - } - }`, - Error: `The argument "channel" is required`, - }, - { - Config: `resource "checkly_alert_channel" "t1" { - slack { - } - }`, - Error: `Missing required argument`, - }, - { - Config: `resource "checkly_alert_channel" "t1" { - webhook { - } - }`, - Error: `The argument "name" is required`, - }, - { - Config: `resource "checkly_alert_channel" "t1" { - webhook { - } - }`, - Error: `The argument "url" is required`, - }, - { - Config: `resource "checkly_alert_channel" "t1" { - opsgenie { - } - }`, - Error: `The argument "api_key" is required`, - }, - { - Config: `resource "checkly_alert_channel" "t1" { - opsgenie { - } - }`, - Error: `The argument "priority" is required`, - }, - { - Config: `resource "checkly_alert_channel" "t1" { - opsgenie { - } - }`, - Error: `The argument "region" is required`, - }, - { - Config: `resource "checkly_alert_channel" "t1" { - pagerduty { - } - }`, - Error: `The argument "service_key" is required`, - }, - } - for key, tc := range cases { - t.Run(fmt.Sprintf("%d", key), func(t *testing.T) { - accTestCase(t, []resource.TestStep{ - { - Config: tc.Config, - ExpectError: regexp.MustCompile(tc.Error), - }, - }) - }) - } -} diff --git a/checkly/resource_check.go b/checkly/resource_check.go deleted file mode 100644 index 7d390b8..0000000 --- a/checkly/resource_check.go +++ /dev/null @@ -1,1115 +0,0 @@ -package checkly - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "sort" - "strings" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/checkly/checkly-go-sdk" -) - -// tfMap is a shorthand alias for convenience; Terraform uses this type a *lot*. -type tfMap = map[string]interface{} - -func resourceCheck() *schema.Resource { - return &schema.Resource{ - Create: resourceCheckCreate, - Read: resourceCheckRead, - Update: resourceCheckUpdate, - Delete: resourceCheckDelete, - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, - }, - Description: "Checks allows you to monitor key webapp flows, backend API's and set up alerting, so you get a notification when things break or slow down.", - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the check.", - }, - "type": { - Type: schema.TypeString, - Required: true, - Description: "The type of the check. Possible values are `API`, `BROWSER`, and `MULTI_STEP`.", - }, - "frequency": { - Type: schema.TypeInt, - Required: true, - ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) { - v := val.(int) - valid := false - validFreqs := []int{0, 1, 2, 5, 10, 15, 30, 60, 120, 180, 360, 720, 1440} - for _, i := range validFreqs { - if v == i { - valid = true - } - } - if !valid { - errs = append(errs, fmt.Errorf("%q must be one of %v, got %d", key, validFreqs, v)) - } - return warns, errs - }, - Description: "The frequency in minutes to run the check. Possible values are `0`, `1`, `2`, `5`, `10`, `15`, `30`, `60`, `120`, `180`, `360`, `720`, and `1440`.", - }, - "frequency_offset": { - Type: schema.TypeInt, - Optional: true, - Description: "This property only valid for API high frequency checks. To create a hight frequency check, the property `frequency` must be `0` and `frequency_offset` could be `10`, `20` or `30`.", - }, - "activated": { - Type: schema.TypeBool, - Required: true, - Description: "Determines if the check is running or not. Possible values `true`, and `false`.", - }, - "muted": { - Type: schema.TypeBool, - Optional: true, - Description: "Determines if any notifications will be sent out when a check fails/degrades/recovers.", - }, - "should_fail": { - Type: schema.TypeBool, - Optional: true, - Description: "Allows to invert the behaviour of when a check is considered to fail. Allows for validating error status like 404.", - }, - "run_parallel": { - Type: schema.TypeBool, - Optional: true, - Description: "Determines if the check should run in all selected locations in parallel or round-robin.", - }, - "locations": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - Description: "An array of one or more data center locations where to run the this check. (Default [\"us-east-1\"])", - }, - "script": { - Type: schema.TypeString, - Optional: true, - Default: "", - Description: "A valid piece of Node.js JavaScript code describing a browser interaction with the Puppeteer/Playwright framework or a reference to an external JavaScript file.", - }, - "degraded_response_time": { - Type: schema.TypeInt, - Optional: true, - Default: 15000, - ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) { - // https://checklyhq.com/docs/api-checks/limits/ - v := val.(int) - if v < 0 || v > 30000 { - errs = append(errs, fmt.Errorf("%q must be 0-30000 ms, got %d", key, v)) - } - return warns, errs - }, - Description: "The response time in milliseconds starting from which a check should be considered degraded. Possible values are between 0 and 30000. (Default `15000`).", - }, - "max_response_time": { - Type: schema.TypeInt, - Optional: true, - Default: 30000, - ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) { - v := val.(int) - // https://checklyhq.com/docs/api-checks/limits/ - if v < 0 || v > 30000 { - errs = append(errs, fmt.Errorf("%q must be 0-30000 ms, got: %d", key, v)) - } - return warns, errs - }, - Description: "The response time in milliseconds starting from which a check should be considered failing. Possible values are between 0 and 30000. (Default `30000`).", - }, - "environment_variables": { - Type: schema.TypeMap, - Optional: true, - Deprecated: "The property `environment_variables` is deprecated and will be removed in a future version. Consider using the new `environment_variable` list.", - Description: "Key/value pairs for setting environment variables during check execution. These are only relevant for browser checks. Use global environment variables whenever possible.", - }, - "environment_variable": { - Type: schema.TypeList, - Optional: true, - Description: "Key/value pairs for setting environment variables during check execution, add locked = true to keep value hidden, add secret = true to create a secret variable. These are only relevant for browser checks. Use global environment variables whenever possible.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "key": { - Type: schema.TypeString, - Required: true, - }, - "value": { - Type: schema.TypeString, - Required: true, - }, - "locked": { - Type: schema.TypeBool, - Optional: true, - Default: false, - }, - "secret": { - Type: schema.TypeBool, - Optional: true, - Default: false, - }, - }, - }, - }, - "double_check": { - Type: schema.TypeBool, - Optional: true, - Description: "Setting this to `true` will trigger a retry when a check fails from the failing region and another, randomly selected region before marking the check as failed.", - Deprecated: "The property `double_check` is deprecated and will be removed in a future version. To enable retries for failed check runs, use the `retry_strategy` property instead.", - }, - "tags": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - Description: "A list of tags for organizing and filtering checks.", - }, - "ssl_check": { - Type: schema.TypeBool, - Optional: true, - Deprecated: "The property `ssl_check` is deprecated and it's ignored by the Checkly Public API. It will be removed in a future version.", - Description: "Determines if the SSL certificate should be validated for expiry.", - }, - "ssl_check_domain": { - Type: schema.TypeString, - Optional: true, - Description: "A valid fully qualified domain name (FQDN) to check its SSL certificate.", - }, - "setup_snippet_id": { - Type: schema.TypeInt, - Optional: true, - Description: "An ID reference to a snippet to use in the setup phase of an API check.", - }, - "teardown_snippet_id": { - Type: schema.TypeInt, - Optional: true, - Description: "An ID reference to a snippet to use in the teardown phase of an API check.", - }, - "local_setup_script": { - Type: schema.TypeString, - Optional: true, - Description: "A valid piece of Node.js code to run in the setup phase.", - }, - "local_teardown_script": { - Type: schema.TypeString, - Optional: true, - Description: "A valid piece of Node.js code to run in the teardown phase.", - }, - "runtime_id": { - Type: schema.TypeString, - Optional: true, - Default: nil, - Description: "The id of the runtime to use for this check.", - }, - "alert_channel_subscription": { - Type: schema.TypeList, - Optional: true, - Description: "An array of channel IDs and whether they're activated or not. If you don't set at least one alert subscription for your check, we won't be able to alert you in case something goes wrong with it.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "channel_id": { - Type: schema.TypeInt, - Required: true, - }, - "activated": { - Type: schema.TypeBool, - Required: true, - }, - }, - }, - }, - "private_locations": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - DefaultFunc: func() (interface{}, error) { - return []tfMap{}, nil - }, - Description: "An array of one or more private locations slugs.", - }, - "alert_settings": { - Type: schema.TypeList, - Optional: true, - Computed: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "escalation_type": { - Type: schema.TypeString, - Optional: true, - Description: "Determines what type of escalation to use. Possible values are `RUN_BASED` or `TIME_BASED`.", - }, - "run_based_escalation": { - Type: schema.TypeList, - Optional: true, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "failed_run_threshold": { - Type: schema.TypeInt, - Optional: true, - Description: "After how many failed consecutive check runs an alert notification should be sent. Possible values are between 1 and 5. (Default `1`).", - }, - }, - }, - }, - "time_based_escalation": { - Type: schema.TypeList, - Optional: true, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "minutes_failing_threshold": { - Type: schema.TypeInt, - Optional: true, - Description: "After how many minutes after a check starts failing an alert should be sent. Possible values are `5`, `10`, `15`, and `30`. (Default `5`).", - }, - }, - }, - }, - "reminders": { - Type: schema.TypeList, - Optional: true, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "amount": { - Type: schema.TypeInt, - Optional: true, - Description: "How many reminders to send out after the initial alert notification. Possible values are `0`, `1`, `2`, `3`, `4`, `5`, and `100000`", - }, - "interval": { - Type: schema.TypeInt, - Optional: true, - Default: 5, - Description: "Possible values are `5`, `10`, `15`, and `30`. (Default `5`).", - }, - }, - }, - }, - "parallel_run_failure_threshold": { - Type: schema.TypeList, - Optional: true, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "enabled": { - Type: schema.TypeBool, - Optional: true, - Default: false, - Description: "Applicable only for checks scheduled in parallel in multiple locations.", - }, - "percentage": { - Type: schema.TypeInt, - Optional: true, - Default: 10, - Description: "Possible values are `10`, `20`, `30`, `40`, `50`, `60`, `70`, `80`, `100`, and `100`. (Default `10`).", - }, - }, - }, - }, - "ssl_certificates": { - Type: schema.TypeSet, - Optional: true, - Deprecated: "This property is deprecated and it's ignored by the Checkly Public API. It will be removed in a future version.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "enabled": { - Type: schema.TypeBool, - Optional: true, - Description: "Determines if alert notifications should be sent for expiring SSL certificates. Possible values `true`, and `false`. (Default `false`).", - }, - "alert_threshold": { - Type: schema.TypeInt, - Optional: true, - ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) { - v := val.(int) - valid := false - validFreqs := []int{3, 7, 14, 30} - for _, i := range validFreqs { - if v == i { - valid = true - } - } - if !valid { - errs = append(errs, fmt.Errorf("%q must be one of %v, got: %d", key, validFreqs, v)) - } - return warns, errs - }, - Description: "How long before SSL certificate expiry to send alerts. Possible values `3`, `7`, `14`, `30`. (Default `3`).", - }, - }, - Description: "At what interval the reminders should be sent.", - }, - }, - }, - }, - }, - "use_global_alert_settings": { - Type: schema.TypeBool, - Optional: true, - Description: "When true, the account level alert settings will be used, not the alert setting defined on this check.", - }, - "request": { - Type: schema.TypeSet, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "method": { - Type: schema.TypeString, - Optional: true, - Default: "GET", - Description: "The HTTP method to use for this API check. Possible values are `GET`, `POST`, `PUT`, `HEAD`, `DELETE`, `PATCH`. (Default `GET`).", - }, - "url": { - Type: schema.TypeString, - Required: true, - }, - "follow_redirects": { - Type: schema.TypeBool, - Optional: true, - }, - "skip_ssl": { - Type: schema.TypeBool, - Optional: true, - }, - "headers": { - Type: schema.TypeMap, - Optional: true, - Computed: true, - DefaultFunc: func() (interface{}, error) { - return []tfMap{}, nil - }, - }, - "query_parameters": { - Type: schema.TypeMap, - Optional: true, - Computed: true, - DefaultFunc: func() (interface{}, error) { - return []tfMap{}, nil - }, - }, - "body": { - Type: schema.TypeString, - Optional: true, - Description: "The body of the request.", - }, - "body_type": { - Type: schema.TypeString, - Optional: true, - Default: "NONE", - Description: "The `Content-Type` header of the request. Possible values `NONE`, `JSON`, `FORM`, `RAW`, and `GRAPHQL`.", - ValidateFunc: func(value interface{}, key string) (warns []string, errs []error) { - v := value.(string) - isValid := false - options := []string{"NONE", "JSON", "FORM", "RAW", "GRAPHQL"} - for _, option := range options { - if v == option { - isValid = true - } - } - if !isValid { - errs = append(errs, fmt.Errorf("%q must be one of %v, got %s", key, options, v)) - } - return warns, errs - }, - }, - "assertion": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "source": { - Type: schema.TypeString, - Required: true, - Description: "The source of the asserted value. Possible values `STATUS_CODE`, `JSON_BODY`, `HEADERS`, `TEXT_BODY`, and `RESPONSE_TIME`.", - }, - "property": { - Type: schema.TypeString, - Optional: true, - }, - "comparison": { - Type: schema.TypeString, - Required: true, - Description: "The type of comparison to be executed between expected and actual value of the assertion. Possible values `EQUALS`, `NOT_EQUALS`, `HAS_KEY`, `NOT_HAS_KEY`, `HAS_VALUE`, `NOT_HAS_VALUE`, `IS_EMPTY`, `NOT_EMPTY`, `GREATER_THAN`, `LESS_THAN`, `CONTAINS`, `NOT_CONTAINS`, `IS_NULL`, and `NOT_NULL`.", - }, - "target": { - Type: schema.TypeString, - Optional: true, - }, - }, - }, - Description: "A request can have multiple assertions.", - }, - "basic_auth": { - Type: schema.TypeSet, - MaxItems: 1, - Optional: true, - Computed: true, - DefaultFunc: func() (interface{}, error) { - return []tfMap{}, nil - }, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "username": { - Type: schema.TypeString, - Required: true, - }, - "password": { - Type: schema.TypeString, - Required: true, - }, - }, - }, - Description: "Set up HTTP basic authentication (username & password).", - }, - "ip_family": { - Type: schema.TypeString, - Optional: true, - Default: "IPv4", - Description: "IP Family to be used when executing the api check. The value can be either IPv4 or IPv6.", - ValidateFunc: func(value interface{}, key string) (warns []string, errs []error) { - v := value.(string) - isValid := false - options := []string{"IPv4", "IPv6"} - for _, option := range options { - if v == option { - isValid = true - } - } - if !isValid { - errs = append(errs, fmt.Errorf("%q must be one of %v, got %s", key, options, v)) - } - return warns, errs - }, - }, - }, - }, - Description: "An API check might have one request config.", - }, - "group_id": { - Type: schema.TypeInt, - Optional: true, - Description: "The id of the check group this check is part of.", - }, - "group_order": { - Type: schema.TypeInt, - Optional: true, - Description: "The position of this check in a check group. It determines in what order checks are run when a group is triggered from the API or from CI/CD.", - }, - "retry_strategy": { - Type: schema.TypeSet, - Optional: true, - Computed: true, - MaxItems: 1, - DefaultFunc: func() (interface{}, error) { - return []tfMap{}, nil - }, - Description: "A strategy for retrying failed check runs.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": { - Type: schema.TypeString, - Required: true, - Description: "Determines which type of retry strategy to use. Possible values are `FIXED`, `LINEAR`, or `EXPONENTIAL`.", - }, - "base_backoff_seconds": { - Type: schema.TypeInt, - Optional: true, - Default: 60, - Description: "The number of seconds to wait before the first retry attempt.", - }, - "max_retries": { - Type: schema.TypeInt, - Optional: true, - Default: 2, - Description: "The maximum number of times to retry the check. Value must be between 1 and 10.", - }, - "max_duration_seconds": { - Type: schema.TypeInt, - Optional: true, - Default: 600, - Description: "The total amount of time to continue retrying the check (maximum 600 seconds).", - }, - "same_region": { - Type: schema.TypeBool, - Optional: true, - Default: true, - Description: "Whether retries should be run in the same region as the initial check run.", - }, - }, - }, - }, - }, - } -} - -func resourceCheckCreate(d *schema.ResourceData, client interface{}) error { - check, err := checkFromResourceData(d) - if err != nil { - return fmt.Errorf("translation error: %w", err) - } - - validationErr := validateRuntimeSupport(check, client) - if validationErr != nil { - return validationErr - } - - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - newCheck, err := client.(checkly.Client).CreateCheck(ctx, check) - - if err != nil { - checkJSON, _ := json.Marshal(check) - return fmt.Errorf("API error 1: %w, Check: %s", err, string(checkJSON)) - } - d.SetId(newCheck.ID) - return resourceCheckRead(d, client) -} - -func resourceCheckRead(d *schema.ResourceData, client interface{}) error { - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - check, err := client.(checkly.Client).GetCheck(ctx, d.Id()) - if err != nil { - if strings.Contains(err.Error(), "404") { - //if resource is deleted remotely, then mark it as - //successfully gone by unsetting it's ID - d.SetId("") - return nil - } - return fmt.Errorf("API error 2: %w", err) - } - return resourceDataFromCheck(check, d) -} - -func resourceCheckUpdate(d *schema.ResourceData, client interface{}) error { - check, err := checkFromResourceData(d) - - if err != nil { - return fmt.Errorf("translation error: %w", err) - } - - validationErr := validateRuntimeSupport(check, client) - if validationErr != nil { - return validationErr - } - - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - _, err = client.(checkly.Client).UpdateCheck(ctx, check.ID, check) - if err != nil { - checkJSON, _ := json.Marshal(check) - return fmt.Errorf("API error 3: Couldn't update check, Error: %w, \nCheck: %s", err, checkJSON) - } - d.SetId(check.ID) - return resourceCheckRead(d, client) -} - -func resourceCheckDelete(d *schema.ResourceData, client interface{}) error { - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - if err := client.(checkly.Client).DeleteCheck(ctx, d.Id()); err != nil { - return fmt.Errorf("API error 4: Couldn't delete Check %s, Error: %w", d.Id(), err) - } - return nil -} - -func resourceDataFromCheck(c *checkly.Check, d *schema.ResourceData) error { - d.Set("name", c.Name) - d.Set("type", c.Type) - d.Set("activated", c.Activated) - d.Set("muted", c.Muted) - d.Set("should_fail", c.ShouldFail) - d.Set("run_parallel", c.RunParallel) - d.Set("locations", c.Locations) - d.Set("script", c.Script) - d.Set("degraded_response_time", c.DegradedResponseTime) - d.Set("max_response_time", c.MaxResponseTime) - d.Set("double_check", c.DoubleCheck) - d.Set("setup_snippet_id", c.SetupSnippetID) - d.Set("teardown_snippet_id", c.TearDownSnippetID) - d.Set("local_setup_script", c.LocalSetupScript) - d.Set("local_teardown_script", c.LocalTearDownScript) - - sort.Strings(c.Tags) - d.Set("tags", c.Tags) - - d.Set("frequency", c.Frequency) - if c.Frequency == 0 { - d.Set("frequency_offset", c.FrequencyOffset) - } - - if c.RuntimeID != nil { - d.Set("runtime_id", *c.RuntimeID) - } - - // ssl_check_domain is only supported for Browser checks - if c.Type == "BROWSER" && c.SSLCheckDomain != "" { - d.Set("ssl_check_domain", c.SSLCheckDomain) - } - - environmentVariables := environmentVariablesFromSet(d.Get("environment_variable").([]interface{})) - if len(environmentVariables) > 0 { - d.Set("environment_variable", c.EnvironmentVariables) - } else if err := d.Set("environment_variables", setFromEnvVars(c.EnvironmentVariables)); err != nil { - return fmt.Errorf("error setting environment variables for resource %s: %s", d.Id(), err) - } - - if err := d.Set("alert_settings", setFromAlertSettings(c.AlertSettings)); err != nil { - return fmt.Errorf("error setting alert settings for resource %s: %w", d.Id(), err) - } - d.Set("use_global_alert_settings", c.UseGlobalAlertSettings) - - if c.Type == checkly.TypeAPI { - err := d.Set("request", setFromRequest(c.Request)) - if err != nil { - return fmt.Errorf("error setting request for resource %s: %w", d.Id(), err) - } - } - d.Set("group_id", c.GroupID) - d.Set("group_order", c.GroupOrder) - d.Set("private_locations", c.PrivateLocations) - d.Set("alert_channel_subscription", c.AlertChannelSubscriptions) - d.Set("retry_strategy", setFromRetryStrategy(c.RetryStrategy)) - d.SetId(d.Id()) - return nil -} - -func setFromEnvVars(evs []checkly.EnvironmentVariable) tfMap { - var s = tfMap{} - for _, ev := range evs { - s[ev.Key] = ev.Value - } - return s -} - -func setFromAlertSettings(as checkly.AlertSettings) []tfMap { - if as.EscalationType == checkly.RunBased { - return []tfMap{ - { - "escalation_type": as.EscalationType, - "run_based_escalation": []tfMap{ - { - "failed_run_threshold": as.RunBasedEscalation.FailedRunThreshold, - }, - }, - "reminders": []tfMap{ - { - "amount": as.Reminders.Amount, - "interval": as.Reminders.Interval, - }, - }, - "parallel_run_failure_threshold": []tfMap{ - { - "enabled": as.ParallelRunFailureThreshold.Enabled, - "percentage": as.ParallelRunFailureThreshold.Percentage, - }, - }, - }, - } - } else { - return []tfMap{ - { - "escalation_type": as.EscalationType, - "time_based_escalation": []tfMap{ - { - "minutes_failing_threshold": as.TimeBasedEscalation.MinutesFailingThreshold, - }, - }, - "reminders": []tfMap{ - { - "amount": as.Reminders.Amount, - "interval": as.Reminders.Interval, - }, - }, - "parallel_run_failure_threshold": []tfMap{ - { - "enabled": as.ParallelRunFailureThreshold.Enabled, - "percentage": as.ParallelRunFailureThreshold.Percentage, - }, - }, - }, - } - } -} - -func setFromRequest(r checkly.Request) []tfMap { - s := tfMap{} - s["method"] = r.Method - s["url"] = r.URL - s["follow_redirects"] = r.FollowRedirects - s["skip_ssl"] = r.SkipSSL - s["body"] = r.Body - s["body_type"] = r.BodyType - s["headers"] = mapFromKeyValues(r.Headers) - s["query_parameters"] = mapFromKeyValues(r.QueryParameters) - s["assertion"] = setFromAssertions(r.Assertions) - s["basic_auth"] = setFromBasicAuth(r.BasicAuth) - s["ip_family"] = r.IPFamily - return []tfMap{s} -} - -func setFromAssertions(assertions []checkly.Assertion) []tfMap { - s := make([]tfMap, len(assertions)) - for i, a := range assertions { - as := tfMap{} - as["source"] = a.Source - as["property"] = a.Property - as["comparison"] = a.Comparison - as["target"] = a.Target - s[i] = as - } - return s -} - -func mapFromKeyValues(kvs []checkly.KeyValue) tfMap { - var s = tfMap{} - for _, item := range kvs { - s[item.Key] = item.Value - } - return s -} - -func setFromBasicAuth(b *checkly.BasicAuth) []tfMap { - if b == nil { - return []tfMap{} - } - return []tfMap{ - { - "username": b.Username, - "password": b.Password, - }, - } -} - -func setFromRetryStrategy(rs *checkly.RetryStrategy) []tfMap { - if rs == nil { - return []tfMap{} - } - return []tfMap{ - { - "type": rs.Type, - "base_backoff_seconds": rs.BaseBackoffSeconds, - "max_retries": rs.MaxRetries, - "max_duration_seconds": rs.MaxDurationSeconds, - "same_region": rs.SameRegion, - }, - } -} - -func checkFromResourceData(d *schema.ResourceData) (checkly.Check, error) { - check := checkly.Check{ - ID: d.Id(), - Name: d.Get("name").(string), - Type: d.Get("type").(string), - Frequency: d.Get("frequency").(int), - Activated: d.Get("activated").(bool), - Muted: d.Get("muted").(bool), - ShouldFail: d.Get("should_fail").(bool), - RunParallel: d.Get("run_parallel").(bool), - Locations: stringsFromSet(d.Get("locations").(*schema.Set)), - Script: d.Get("script").(string), - DegradedResponseTime: d.Get("degraded_response_time").(int), - MaxResponseTime: d.Get("max_response_time").(int), - DoubleCheck: d.Get("double_check").(bool), - Tags: stringsFromSet(d.Get("tags").(*schema.Set)), - SSLCheck: d.Get("ssl_check").(bool), - SSLCheckDomain: d.Get("ssl_check_domain").(string), - SetupSnippetID: int64(d.Get("setup_snippet_id").(int)), - TearDownSnippetID: int64(d.Get("teardown_snippet_id").(int)), - LocalSetupScript: d.Get("local_setup_script").(string), - LocalTearDownScript: d.Get("local_teardown_script").(string), - AlertSettings: alertSettingsFromSet(d.Get("alert_settings").([]interface{})), - UseGlobalAlertSettings: d.Get("use_global_alert_settings").(bool), - GroupID: int64(d.Get("group_id").(int)), - GroupOrder: d.Get("group_order").(int), - AlertChannelSubscriptions: alertChannelSubscriptionsFromSet(d.Get("alert_channel_subscription").([]interface{})), - RetryStrategy: retryStrategyFromSet(d.Get("retry_strategy").(*schema.Set)), - } - - runtimeId := d.Get("runtime_id").(string) - if runtimeId == "" { - check.RuntimeID = nil - } else { - check.RuntimeID = &runtimeId - } - - environmentVariables, err := getResourceEnvironmentVariables(d) - if err != nil { - return checkly.Check{}, err - } - check.EnvironmentVariables = environmentVariables - - privateLocations := stringsFromSet(d.Get("private_locations").(*schema.Set)) - check.PrivateLocations = &privateLocations - - if check.Type == checkly.TypeAPI { - // this will prevent subsequent apply from causing a tf config change in browser checks - check.Request = requestFromSet(d.Get("request").(*schema.Set)) - check.FrequencyOffset = d.Get("frequency_offset").(int) - - if check.Frequency == 0 && (check.FrequencyOffset != 10 && check.FrequencyOffset != 20 && check.FrequencyOffset != 30) { - return check, errors.New("when property frequency is 0, frequency_offset must be 10, 20 or 30") - } - - if check.SSLCheckDomain != "" { - return check, errors.New("ssl_check_domain is allowed only for Browser checks") - } - } - - if check.Type == checkly.TypeBrowser && check.Frequency == 0 { - return check, errors.New("property frequency could only be 0 for API checks") - } - - return check, nil -} - -func stringsFromSet(s *schema.Set) []string { - r := make([]string, s.Len()) - for i, item := range s.List() { - r[i] = item.(string) - } - return r -} - -func assertionsFromSet(s *schema.Set) []checkly.Assertion { - r := make([]checkly.Assertion, s.Len()) - for i, item := range s.List() { - res := item.(tfMap) - r[i] = checkly.Assertion{ - Source: res["source"].(string), - Property: res["property"].(string), - Comparison: res["comparison"].(string), - Target: res["target"].(string), - } - } - return r -} - -func basicAuthFromSet(s *schema.Set) *checkly.BasicAuth { - if s.Len() == 0 { - return nil - } - res := s.List()[0].(tfMap) - return &checkly.BasicAuth{ - Username: res["username"].(string), - Password: res["password"].(string), - } -} - -func alertSettingsFromSet(s []interface{}) checkly.AlertSettings { - if len(s) == 0 { - return checkly.AlertSettings{ - EscalationType: checkly.RunBased, - RunBasedEscalation: checkly.RunBasedEscalation{ - FailedRunThreshold: 1, - }, - } - } - res := s[0].(tfMap) - alertSettings := checkly.AlertSettings{ - EscalationType: res["escalation_type"].(string), - Reminders: remindersFromSet(res["reminders"].([]interface{})), - ParallelRunFailureThreshold: parallelRunFailureThresholdFromSet(res["parallel_run_failure_threshold"].([]interface{})), - } - - if alertSettings.EscalationType == checkly.RunBased { - alertSettings.RunBasedEscalation = runBasedEscalationFromSet(res["run_based_escalation"].([]interface{})) - } else { - alertSettings.TimeBasedEscalation = timeBasedEscalationFromSet(res["time_based_escalation"].([]interface{})) - } - - return alertSettings -} - -func retryStrategyFromSet(s *schema.Set) *checkly.RetryStrategy { - if s.Len() == 0 { - return nil - } - res := s.List()[0].(tfMap) - return &checkly.RetryStrategy{ - Type: res["type"].(string), - BaseBackoffSeconds: res["base_backoff_seconds"].(int), - MaxRetries: res["max_retries"].(int), - MaxDurationSeconds: res["max_duration_seconds"].(int), - SameRegion: res["same_region"].(bool), - } -} - -func alertChannelSubscriptionsFromSet(s []interface{}) []checkly.AlertChannelSubscription { - res := []checkly.AlertChannelSubscription{} - if len(s) == 0 { - return res - } - for _, it := range s { - tm := it.(tfMap) - chid := tm["channel_id"].(int) - activated := tm["activated"].(bool) - res = append(res, checkly.AlertChannelSubscription{ - Activated: activated, - ChannelID: int64(chid), - }) - } - return res -} - -func environmentVariablesFromSet(s []interface{}) []checkly.EnvironmentVariable { - res := []checkly.EnvironmentVariable{} - if len(s) == 0 { - return res - } - for _, it := range s { - tm := it.(tfMap) - key := tm["key"].(string) - value := tm["value"].(string) - locked := tm["locked"].(bool) - secret := tm["secret"].(bool) - res = append(res, checkly.EnvironmentVariable{ - Key: key, - Value: value, - Locked: locked, - Secret: secret, - }) - } - - return res -} - -func runBasedEscalationFromSet(s []interface{}) checkly.RunBasedEscalation { - if len(s) == 0 { - return checkly.RunBasedEscalation{} - } - res := s[0].(tfMap) - return checkly.RunBasedEscalation{ - FailedRunThreshold: res["failed_run_threshold"].(int), - } -} - -func timeBasedEscalationFromSet(s []interface{}) checkly.TimeBasedEscalation { - if len(s) == 0 { - return checkly.TimeBasedEscalation{} - } - res := s[0].(tfMap) - return checkly.TimeBasedEscalation{ - MinutesFailingThreshold: res["minutes_failing_threshold"].(int), - } -} - -func remindersFromSet(s []interface{}) checkly.Reminders { - if len(s) == 0 { - return checkly.Reminders{} - } - res := s[0].(tfMap) - return checkly.Reminders{ - Amount: res["amount"].(int), - Interval: res["interval"].(int), - } -} - -func parallelRunFailureThresholdFromSet(s []interface{}) checkly.ParallelRunFailureThreshold { - if len(s) == 0 { - return checkly.ParallelRunFailureThreshold{} - } - res := s[0].(tfMap) - return checkly.ParallelRunFailureThreshold{ - Enabled: res["enabled"].(bool), - Percentage: res["percentage"].(int), - } -} - -func requestFromSet(s *schema.Set) checkly.Request { - if s.Len() == 0 { - return checkly.Request{} - } - res := s.List()[0].(tfMap) - return checkly.Request{ - Method: res["method"].(string), - URL: res["url"].(string), - FollowRedirects: res["follow_redirects"].(bool), - SkipSSL: res["skip_ssl"].(bool), - Body: res["body"].(string), - BodyType: res["body_type"].(string), - Headers: keyValuesFromMap(res["headers"].(tfMap)), - QueryParameters: keyValuesFromMap(res["query_parameters"].(tfMap)), - Assertions: assertionsFromSet(res["assertion"].(*schema.Set)), - BasicAuth: basicAuthFromSet(res["basic_auth"].(*schema.Set)), - IPFamily: res["ip_family"].(string), - } -} - -func envVarsFromMap(m map[string]interface{}) []checkly.EnvironmentVariable { - r := make([]checkly.EnvironmentVariable, 0, len(m)) - for k, v := range m { - s, ok := v.(string) - if !ok { - panic(fmt.Errorf("could not convert environment variable value %v to string", v)) - } - - r = append(r, checkly.EnvironmentVariable{ - Key: k, - Value: s, - }) - - } - return r -} - -func keyValuesFromMap(m map[string]interface{}) []checkly.KeyValue { - r := make([]checkly.KeyValue, 0, len(m)) - for k, v := range m { - s, ok := v.(string) - if !ok { - panic(fmt.Errorf("could not convert environment variable value %v to string", v)) - } - r = append(r, checkly.KeyValue{ - Key: k, - Value: s, - }) - } - return r -} - -func getResourceEnvironmentVariables(d *schema.ResourceData) ([]checkly.EnvironmentVariable, error) { - deprecatedEnvironmentVariables := envVarsFromMap(d.Get("environment_variables").(tfMap)) - environmentVariables := environmentVariablesFromSet(d.Get("environment_variable").([]interface{})) - - if len(environmentVariables) > 0 && len(deprecatedEnvironmentVariables) > 0 { - return nil, errors.New("can't use both \"environment_variables\" and \"environment_variable\" on checkly_check_group resource") - } - - if len(environmentVariables) > 0 { - return environmentVariables, nil - } - - return deprecatedEnvironmentVariables, nil -} - -func validateRuntimeSupport(check checkly.Check, client interface{}) error { - // If the check has a runtime ID set, then validate that the runtime supports multistep. - // Note that if the runtime ID is coming from the account defaults or group, then we don't validate it. - // Adding validation there as well would be a nice improvement, though. - if check.Type == "MULTI_STEP" && check.RuntimeID != nil { - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - checkRuntime, err := client.(checkly.Client).GetRuntime(ctx, *check.RuntimeID) - - if err != nil { - return fmt.Errorf("API error while fetching runtimes: %w", err) - } - - if !checkRuntime.MultiStepSupport { - return fmt.Errorf("runtime %s does not support MULTI_STEP checks", *check.RuntimeID) - } - } - return nil -} diff --git a/checkly/resource_check_group.go b/checkly/resource_check_group.go deleted file mode 100644 index e43df9c..0000000 --- a/checkly/resource_check_group.go +++ /dev/null @@ -1,621 +0,0 @@ -package checkly - -import ( - "context" - "fmt" - "sort" - "strconv" - "strings" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - checkly "github.com/checkly/checkly-go-sdk" -) - -func resourceCheckGroup() *schema.Resource { - return &schema.Resource{ - Create: resourceCheckGroupCreate, - Read: resourceCheckGroupRead, - Update: resourceCheckGroupUpdate, - Delete: resourceCheckGroupDelete, - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, - }, - Description: "Check groups allow you to group together a set of related checks, which can also share default settings for various attributes.", - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the check group.", - }, - "concurrency": { - Type: schema.TypeInt, - Required: true, - Description: "Determines how many checks are run concurrently when triggering a check group from CI/CD or through the API.", - }, - "activated": { - Type: schema.TypeBool, - Required: true, - Description: "Determines if the checks in the group are running or not.", - }, - "muted": { - Type: schema.TypeBool, - Optional: true, - Description: "Determines if any notifications will be sent out when a check in this group fails and/or recovers.", - }, - "run_parallel": { - Type: schema.TypeBool, - Optional: true, - Description: "Determines if the checks in the group should run in all selected locations in parallel or round-robin.", - }, - "locations": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - Description: "An array of one or more data center locations where to run the checks.", - }, - "private_locations": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - DefaultFunc: func() (interface{}, error) { - return []tfMap{}, nil - }, - Description: "An array of one or more private locations slugs.", - }, - "environment_variables": { - Type: schema.TypeMap, - Optional: true, - Deprecated: "The property `environment_variables` is deprecated and will be removed in a future version. Consider using the new `environment_variable` list.", - Description: "Key/value pairs for setting environment variables during check execution. These are only relevant for browser checks. Use global environment variables whenever possible.", - }, - "environment_variable": { - Type: schema.TypeList, - Optional: true, - Description: "Key/value pairs for setting environment variables during check execution, add locked = true to keep value hidden, add secret = true to create a secret variable. These are only relevant for browser checks. Use global environment variables whenever possible.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "key": { - Type: schema.TypeString, - Required: true, - }, - "value": { - Type: schema.TypeString, - Required: true, - }, - "locked": { - Type: schema.TypeBool, - Optional: true, - Default: false, - }, - "secret": { - Type: schema.TypeBool, - Optional: true, - Default: false, - }, - }, - }, - }, - "double_check": { - Type: schema.TypeBool, - Optional: true, - Description: "Setting this to `true` will trigger a retry when a check fails from the failing region and another, randomly selected region before marking the check as failed.", - Deprecated: "The property `double_check` is deprecated and will be removed in a future version. To enable retries for failed check runs, use the `retry_strategy` property instead.", - }, - "tags": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - Description: "Tags for organizing and filtering checks.", - }, - "setup_snippet_id": { - Type: schema.TypeInt, - Optional: true, - Description: "An ID reference to a snippet to use in the setup phase of an API check.", - }, - "teardown_snippet_id": { - Type: schema.TypeInt, - Optional: true, - Description: "An ID reference to a snippet to use in the teardown phase of an API check.", - }, - "local_setup_script": { - Type: schema.TypeString, - Optional: true, - Description: "A valid piece of Node.js code to run in the setup phase of an API check in this group.", - }, - "local_teardown_script": { - Type: schema.TypeString, - Optional: true, - Description: "A valid piece of Node.js code to run in the teardown phase of an API check in this group.", - }, - "runtime_id": { - Type: schema.TypeString, - Optional: true, - Default: nil, - Description: "The id of the runtime to use for this group.", - }, - "alert_channel_subscription": { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "channel_id": { - Type: schema.TypeInt, - Required: true, - }, - "activated": { - Type: schema.TypeBool, - Required: true, - }, - }, - }, - }, - "alert_settings": { - Type: schema.TypeList, - Optional: true, - Computed: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "escalation_type": { - Type: schema.TypeString, - Optional: true, - Default: checkly.RunBased, - Description: "Determines what type of escalation to use. Possible values are `RUN_BASED` or `TIME_BASED`.", - }, - "run_based_escalation": { - Type: schema.TypeList, - Optional: true, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "failed_run_threshold": { - Type: schema.TypeInt, - Optional: true, - Description: "After how many failed consecutive check runs an alert notification should be sent. Possible values are between 1 and 5. (Default `1`).", - }, - }, - }, - }, - "time_based_escalation": { - Type: schema.TypeList, - Optional: true, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "minutes_failing_threshold": { - Type: schema.TypeInt, - Optional: true, - Description: "After how many minutes after a check starts failing an alert should be sent. Possible values are `5`, `10`, `15`, and `30`. (Default `5`).", - }, - }, - }, - }, - "reminders": { - Type: schema.TypeList, - Optional: true, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "amount": { - Type: schema.TypeInt, - Optional: true, - Description: "How many reminders to send out after the initial alert notification. Possible values are `0`, `1`, `2`, `3`, `4`, `5`, and `100000`", - }, - "interval": { - Type: schema.TypeInt, - Optional: true, - Default: 5, - Description: "Possible values are `5`, `10`, `15`, and `30`. (Default `5`).", - }, - }, - }, - }, - "parallel_run_failure_threshold": { - Type: schema.TypeList, - Optional: true, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "enabled": { - Type: schema.TypeBool, - Optional: true, - Default: false, - Description: "Applicable only for checks scheduled in parallel in multiple locations.", - }, - "percentage": { - Type: schema.TypeInt, - Optional: true, - Default: 10, - Description: "Possible values are `10`, `20`, `30`, `40`, `50`, `60`, `70`, `80`, `100`, and `100`. (Default `10`).", - }, - }, - }, - }, - "ssl_certificates": { - Type: schema.TypeSet, - Optional: true, - Deprecated: "This property is deprecated and it's ignored by the Checkly Public API. It will be removed in a future version.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "enabled": { - Type: schema.TypeBool, - Optional: true, - Description: "Determines if alert notifications should be sent for expiring SSL certificates.", - }, - "alert_threshold": { - Type: schema.TypeInt, - Optional: true, - ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) { - v := val.(int) - valid := false - validFreqs := []int{3, 7, 14, 30} - for _, i := range validFreqs { - if v == i { - valid = true - } - } - if !valid { - errs = append(errs, fmt.Errorf("%q must be one of %v, got: %d", key, validFreqs, v)) - } - return warns, errs - }, - Description: "At what moment in time to start alerting on SSL certificates. Possible values `3`, `7`, `14`, `30`. (Default `3`).", - }, - }, - }, - }, - }, - }, - }, - "use_global_alert_settings": { - Type: schema.TypeBool, - Optional: true, - Description: "When true, the account level alert settings will be used, not the alert setting defined on this check group.", - }, - "api_check_defaults": { - Type: schema.TypeSet, - MaxItems: 1, - Optional: true, - Computed: true, - DefaultFunc: func() (interface{}, error) { - return []tfMap{ - tfMap{ - "url": "", - "headers": []tfMap{}, - "query_parameters": []tfMap{}, - "basic_auth": tfMap{}, - }}, nil - }, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "url": { - Type: schema.TypeString, - Required: true, - Description: "The base url for this group which you can reference with the `GROUP_BASE_URL` variable in all group checks.", - }, - "headers": { - Type: schema.TypeMap, - Optional: true, - Computed: true, - DefaultFunc: func() (interface{}, error) { - return []tfMap{}, nil - }, - }, - "query_parameters": { - Type: schema.TypeMap, - Optional: true, - Computed: true, - DefaultFunc: func() (interface{}, error) { - return []tfMap{}, nil - }, - }, - "assertion": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "source": { - Type: schema.TypeString, - Required: true, - Description: "The source of the asserted value. Possible values `STATUS_CODE`, `JSON_BODY`, `HEADERS`, `TEXT_BODY`, and `RESPONSE_TIME`.", - }, - "property": { - Type: schema.TypeString, - Optional: true, - }, - "comparison": { - Type: schema.TypeString, - Required: true, - Description: "The type of comparison to be executed between expected and actual value of the assertion. Possible values `EQUALS`, `NOT_EQUALS`, `HAS_KEY`, `NOT_HAS_KEY`, `HAS_VALUE`, `NOT_HAS_VALUE`, `IS_EMPTY`, `NOT_EMPTY`, `GREATER_THAN`, `LESS_THAN`, `CONTAINS`, `NOT_CONTAINS`, `IS_NULL`, and `NOT_NULL`.", - }, - "target": { - Type: schema.TypeString, - Required: true, - }, - }, - }, - }, - "basic_auth": { - Type: schema.TypeSet, - MaxItems: 1, - Optional: true, - Computed: true, - DefaultFunc: func() (interface{}, error) { - return []tfMap{}, nil - }, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "username": { - Type: schema.TypeString, - Required: true, - }, - "password": { - Type: schema.TypeString, - Required: true, - }, - }, - }, - }, - }, - }, - }, - "retry_strategy": { - Type: schema.TypeSet, - Optional: true, - Computed: true, - MaxItems: 1, - DefaultFunc: func() (interface{}, error) { - return []tfMap{}, nil - }, - Description: "A strategy for retrying failed check runs.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": { - Type: schema.TypeString, - Required: true, - Description: "Determines which type of retry strategy to use. Possible values are `FIXED`, `LINEAR`, or `EXPONENTIAL`.", - }, - "base_backoff_seconds": { - Type: schema.TypeInt, - Optional: true, - Default: 60, - Description: "The number of seconds to wait before the first retry attempt.", - }, - "max_retries": { - Type: schema.TypeInt, - Optional: true, - Default: 2, - Description: "The maximum number of times to retry the check. Value must be between 1 and 10.", - }, - "max_duration_seconds": { - Type: schema.TypeInt, - Optional: true, - Default: 600, - Description: "The total amount of time to continue retrying the check (maximum 600 seconds).", - }, - "same_region": { - Type: schema.TypeBool, - Optional: true, - Default: true, - Description: "Whether retries should be run in the same region as the initial check run.", - }, - }, - }, - }, - }, - } -} - -func resourceCheckGroupCreate(d *schema.ResourceData, client interface{}) error { - group, err := checkGroupFromResourceData(d) - if err != nil { - return fmt.Errorf("translation error: %w", err) - } - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - gotGroup, err := client.(checkly.Client).CreateGroup(ctx, group) - if err != nil { - return fmt.Errorf("API error11: %w", err) - } - d.SetId(fmt.Sprintf("%d", gotGroup.ID)) - return resourceCheckGroupRead(d, client) -} - -func resourceCheckGroupRead(d *schema.ResourceData, client interface{}) error { - ID, err := strconv.ParseInt(d.Id(), 10, 64) - if err != nil { - return fmt.Errorf("ID %s is not numeric: %w", d.Id(), err) - } - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - group, err := client.(checkly.Client).GetGroup(ctx, ID) - if err != nil { - if strings.Contains(err.Error(), "404") { - //if resource is deleted remotely, then mark it as - //successfully gone by unsetting it's ID - d.SetId("") - return nil - } - return fmt.Errorf("API error12: %w", err) - } - return resourceDataFromCheckGroup(group, d) -} - -func resourceCheckGroupUpdate(d *schema.ResourceData, client interface{}) error { - group, err := checkGroupFromResourceData(d) - if err != nil { - return fmt.Errorf("translation error: %w", err) - } - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - _, err = client.(checkly.Client).UpdateGroup(ctx, group.ID, group) - if err != nil { - return fmt.Errorf("API error13: %w", err) - } - d.SetId(fmt.Sprintf("%d", group.ID)) - return resourceCheckGroupRead(d, client) -} - -func resourceCheckGroupDelete(d *schema.ResourceData, client interface{}) error { - ID, err := strconv.ParseInt(d.Id(), 10, 64) - if err != nil { - return fmt.Errorf("ID %s is not numeric: %w", d.Id(), err) - } - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - if err := client.(checkly.Client).DeleteGroup(ctx, ID); err != nil { - return fmt.Errorf("API error14: %w", err) - } - return nil -} - -func resourceDataFromCheckGroup(g *checkly.Group, d *schema.ResourceData) error { - d.Set("name", g.Name) - d.Set("concurrency", g.Concurrency) - d.Set("activated", g.Activated) - d.Set("muted", g.Muted) - d.Set("run_parallel", g.RunParallel) - d.Set("locations", g.Locations) - d.Set("double_check", g.DoubleCheck) - d.Set("setup_snippet_id", g.SetupSnippetID) - d.Set("teardown_snippet_id", g.TearDownSnippetID) - d.Set("local_setup_script", g.LocalSetupScript) - d.Set("local_teardown_script", g.LocalTearDownScript) - d.Set("alert_channel_subscription", g.AlertChannelSubscriptions) - d.Set("private_locations", g.PrivateLocations) - - sort.Strings(g.Tags) - d.Set("tags", g.Tags) - - environmentVariables := environmentVariablesFromSet(d.Get("environment_variable").([]interface{})) - if len(environmentVariables) > 0 { - d.Set("environment_variable", g.EnvironmentVariables) - } else if err := d.Set("environment_variables", setFromEnvVars(g.EnvironmentVariables)); err != nil { - return fmt.Errorf("error setting environment variables for resource %s: %s", d.Id(), err) - } - - if g.RuntimeID != nil { - d.Set("runtime_id", *g.RuntimeID) - } - - if err := d.Set("alert_settings", setFromAlertSettings(g.AlertSettings)); err != nil { - return fmt.Errorf("error setting alert settings for resource %s: %s", d.Id(), err) - } - d.Set("use_global_alert_settings", g.UseGlobalAlertSettings) - - if err := d.Set("api_check_defaults", setFromAPICheckDefaults(g.APICheckDefaults)); err != nil { - return fmt.Errorf("error setting request for resource %s: %s", d.Id(), err) - } - - d.Set("retry_strategy", setFromRetryStrategy(g.RetryStrategy)) - - d.SetId(d.Id()) - return nil -} - -func checkGroupFromResourceData(d *schema.ResourceData) (checkly.Group, error) { - ID, err := strconv.ParseInt(d.Id(), 10, 64) - if err != nil { - if d.Id() != "" { - return checkly.Group{}, err - } - ID = 0 - } - - group := checkly.Group{ - ID: ID, - Name: d.Get("name").(string), - Concurrency: d.Get("concurrency").(int), - Activated: d.Get("activated").(bool), - Muted: d.Get("muted").(bool), - RunParallel: d.Get("run_parallel").(bool), - Locations: stringsFromSet(d.Get("locations").(*schema.Set)), - DoubleCheck: d.Get("double_check").(bool), - Tags: stringsFromSet(d.Get("tags").(*schema.Set)), - SetupSnippetID: int64(d.Get("setup_snippet_id").(int)), - TearDownSnippetID: int64(d.Get("teardown_snippet_id").(int)), - LocalSetupScript: d.Get("local_setup_script").(string), - LocalTearDownScript: d.Get("local_teardown_script").(string), - AlertSettings: alertSettingsFromSet(d.Get("alert_settings").([]interface{})), - UseGlobalAlertSettings: d.Get("use_global_alert_settings").(bool), - APICheckDefaults: apiCheckDefaultsFromSet(d.Get("api_check_defaults").(*schema.Set)), - AlertChannelSubscriptions: alertChannelSubscriptionsFromSet(d.Get("alert_channel_subscription").([]interface{})), - RetryStrategy: retryStrategyFromSet(d.Get("retry_strategy").(*schema.Set)), - } - - runtimeId := d.Get("runtime_id").(string) - if runtimeId == "" { - group.RuntimeID = nil - } else { - group.RuntimeID = &runtimeId - } - - environmentVariables, err := getResourceEnvironmentVariables(d) - if err != nil { - return checkly.Group{}, err - } - group.EnvironmentVariables = environmentVariables - - privateLocations := stringsFromSet(d.Get("private_locations").(*schema.Set)) - group.PrivateLocations = &privateLocations - - return group, nil -} - -func setFromAPICheckDefaults(a checkly.APICheckDefaults) []tfMap { - s := tfMap{} - s["url"] = a.BaseURL - s["headers"] = mapFromKeyValues(a.Headers) - s["query_parameters"] = mapFromKeyValues(a.QueryParameters) - s["assertion"] = setFromAssertions(a.Assertions) - s["basic_auth"] = checkGroupSetFromBasicAuth(a.BasicAuth) - return []tfMap{s} -} - -func apiCheckDefaultsFromSet(s *schema.Set) checkly.APICheckDefaults { - if s.Len() == 0 { - return checkly.APICheckDefaults{} - } - res := s.List()[0].(tfMap) - - return checkly.APICheckDefaults{ - BaseURL: res["url"].(string), - Headers: keyValuesFromMap(res["headers"].(tfMap)), - QueryParameters: keyValuesFromMap(res["query_parameters"].(tfMap)), - Assertions: assertionsFromSet(res["assertion"].(*schema.Set)), - BasicAuth: checkGroupBasicAuthFromSet(res["basic_auth"].(*schema.Set)), - } -} - -func checkGroupSetFromBasicAuth(b checkly.BasicAuth) []tfMap { - if b.Username == "" && b.Password == "" { - return []tfMap{} - } - return []tfMap{ - { - "username": b.Username, - "password": b.Password, - }, - } -} - -func checkGroupBasicAuthFromSet(s *schema.Set) checkly.BasicAuth { - if s.Len() == 0 { - return checkly.BasicAuth{ - Username: "", - Password: "", - } - } - res := s.List()[0].(tfMap) - return checkly.BasicAuth{ - Username: res["username"].(string), - Password: res["password"].(string), - } -} diff --git a/checkly/resource_check_group_test.go b/checkly/resource_check_group_test.go deleted file mode 100644 index eabc14a..0000000 --- a/checkly/resource_check_group_test.go +++ /dev/null @@ -1,427 +0,0 @@ -package checkly - -import ( - "regexp" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - - "github.com/checkly/checkly-go-sdk" -) - -func TestEncodeDecodeGroupResource(t *testing.T) { - res := resourceCheckGroup() - data := res.TestResourceData() - resourceDataFromCheckGroup(&wantGroup, data) - gotGroup, err := checkGroupFromResourceData(data) - if err != nil { - t.Fatal(err) - } - if !cmp.Equal(wantGroup, gotGroup) { - t.Error(cmp.Diff(wantGroup, gotGroup)) - } -} - -var wantGroup = checkly.Group{ - Name: "test", - Activated: true, - Muted: false, - Tags: []string{"auto"}, - Locations: []string{"eu-west-1"}, - PrivateLocations: &[]string{}, - Concurrency: 3, - APICheckDefaults: checkly.APICheckDefaults{ - BaseURL: "example.com/api/test", - Headers: []checkly.KeyValue{ - { - Key: "X-Test", - Value: "foo", - }, - }, - QueryParameters: []checkly.KeyValue{ - { - Key: "query", - Value: "foo", - }, - }, - Assertions: []checkly.Assertion{ - { - Source: checkly.StatusCode, - Comparison: checkly.Equals, - Target: "200", - }, - }, - BasicAuth: checkly.BasicAuth{ - Username: "user", - Password: "pass", - }, - }, - EnvironmentVariables: []checkly.EnvironmentVariable{ - { - Key: "ENVTEST", - Value: "Hello world", - }, - }, - DoubleCheck: true, - UseGlobalAlertSettings: false, - AlertSettings: checkly.AlertSettings{ - EscalationType: checkly.RunBased, - RunBasedEscalation: checkly.RunBasedEscalation{ - FailedRunThreshold: 1, - }, - Reminders: checkly.Reminders{ - Amount: 0, - Interval: 5, - }, - }, - LocalSetupScript: "setup-test", - LocalTearDownScript: "teardown-test", - AlertChannelSubscriptions: []checkly.AlertChannelSubscription{}, -} - -func TestAccCheckGroupEmptyConfig(t *testing.T) { - config := `resource "checkly_check_group" "test" {}` - accTestCase(t, []resource.TestStep{ - { - Config: config, - ExpectError: regexp.MustCompile(`The argument "name" is required`), - }, - { - Config: config, - ExpectError: regexp.MustCompile(`The argument "concurrency" is required`), - }, - { - Config: config, - ExpectError: regexp.MustCompile(`The argument "activated" is required`), - }, - }) -} - -func TestAccCheckGroupInvalid(t *testing.T) { - accTestCase(t, []resource.TestStep{ - { - Config: testCheckGroup_invalid, - ExpectError: regexp.MustCompile(`Inappropriate value for attribute "locations"`), - }, - { - Config: testCheckGroup_invalid, - ExpectError: regexp.MustCompile(`Inappropriate value for attribute "muted"`), - }, - { - Config: testCheckGroup_invalid, - ExpectError: regexp.MustCompile(`Inappropriate value for attribute "activated"`), - }, - { - Config: testCheckGroup_invalid, - ExpectError: regexp.MustCompile(`The argument "concurrency" is required`), - }, - { - Config: testCheckGroup_invalid, - ExpectError: regexp.MustCompile(`Missing required argument`), - }, - }) -} - -func TestAccCheckGroupBasic(t *testing.T) { - accTestCase(t, []resource.TestStep{ - { - Config: testCheckGroup_basic, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "checkly_check_group.test", - "name", - "test", - ), - resource.TestCheckResourceAttr( - "checkly_check_group.test", - "activated", - "true", - ), - resource.TestCheckResourceAttr( - "checkly_check_group.test", - "muted", - "false", - ), - resource.TestCheckResourceAttr( - "checkly_check_group.test", - "concurrency", - "3", - ), - resource.TestCheckResourceAttr( - "checkly_check_group.test", - "locations.#", - "2", - ), - testCheckResourceAttrExpr( - "checkly_check_group.test", - "locations.*", - "us-east-1", - ), - testCheckResourceAttrExpr( - "checkly_check_group.test", - "locations.*", - "eu-central-1", - ), - ), - }, - }) -} - -func TestAccCheckGroupWithApiDefaults(t *testing.T) { - accTestCase(t, []resource.TestStep{ - { - Config: testCheckGroup_withApiDefaults, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "checkly_check_group.test", - "name", - "test", - ), - testCheckResourceAttrExpr( - "checkly_check_group.test", - "api_check_defaults.*.url", - "http://api.example.com/", - ), - ), - }, - }) -} - -func TestAccCheckGroupFull(t *testing.T) { - accTestCase(t, []resource.TestStep{ - { - Config: testCheckGroup_full, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "checkly_check_group.test", - "name", - "test", - ), - resource.TestCheckResourceAttr( - "checkly_check_group.test", - "activated", - "true", - ), - resource.TestCheckResourceAttr( - "checkly_check_group.test", - "muted", - "false", - ), - resource.TestCheckResourceAttr( - "checkly_check_group.test", - "concurrency", - "3", - ), - resource.TestCheckResourceAttr( - "checkly_check_group.test", - "double_check", - "true", - ), - resource.TestCheckResourceAttr( - "checkly_check_group.test", - "use_global_alert_settings", - "false", - ), - resource.TestCheckResourceAttr( - "checkly_check_group.test", - "locations.#", - "2", - ), - testCheckResourceAttrExpr( - "checkly_check_group.test", - "locations.*", - "us-east-1", - ), - testCheckResourceAttrExpr( - "checkly_check_group.test", - "locations.*", - "eu-central-1", - ), - resource.TestCheckResourceAttr( - "checkly_check_group.test", - "environment_variables.FOO", - "BAR", - ), - testCheckResourceAttrExpr( - "checkly_check_group.test", - "alert_settings.*.escalation_type", - "RUN_BASED", - ), - testCheckResourceAttrExpr( - "checkly_check_group.test", - "alert_settings.*.reminders.#", - "1", - ), - testCheckResourceAttrExpr( - "checkly_check_group.test", - "alert_settings.*.reminders.*.amount", - "2", - ), - testCheckResourceAttrExpr( - "checkly_check_group.test", - "alert_settings.*.reminders.*.interval", - "5", - ), - testCheckResourceAttrExpr( - "checkly_check_group.test", - "alert_settings.*.run_based_escalation.#", - "1", - ), - testCheckResourceAttrExpr( - "checkly_check_group.test", - "alert_settings.*.run_based_escalation.*.failed_run_threshold", - "1", - ), - testCheckResourceAttrExpr( - "checkly_check_group.test", - "api_check_defaults.#", - "1", - ), - testCheckResourceAttrExpr( - "checkly_check_group.test", - "api_check_defaults.*.assertion.#", - "1", - ), - testCheckResourceAttrExpr( - "checkly_check_group.test", - "api_check_defaults.*.assertion.*.comparison", - "EQUALS", - ), - testCheckResourceAttrExpr( - "checkly_check_group.test", - "api_check_defaults.*.assertion.*.property", - "", - ), - testCheckResourceAttrExpr( - "checkly_check_group.test", - "api_check_defaults.*.assertion.*.source", - "STATUS_CODE", - ), - testCheckResourceAttrExpr( - "checkly_check_group.test", - "api_check_defaults.*.assertion.*.target", - "200", - ), - testCheckResourceAttrExpr( - "checkly_check_group.test", - "api_check_defaults.*.basic_auth.#", - "1", - ), - testCheckResourceAttrExpr( - "checkly_check_group.test", - "api_check_defaults.*.basic_auth.*.password", - "pass", - ), - testCheckResourceAttrExpr( - "checkly_check_group.test", - "api_check_defaults.*.basic_auth.*.username", - "user", - ), - testCheckResourceAttrExpr( - "checkly_check_group.test", - "api_check_defaults.*.headers.X-Test", - "foo", - ), - testCheckResourceAttrExpr( - "checkly_check_group.test", - "api_check_defaults.*.query_parameters.query", - "foo", - ), - testCheckResourceAttrExpr( - "checkly_check_group.test", - "api_check_defaults.*.url", - "http://example.com/", - ), - ), - }, - }) -} - -const testCheckGroup_invalid = ` - resource "checkly_check_group" "test" { - name = "test" - activated = "invalid" - muted = "invalid" - locations = "invalid" - } -` - -const testCheckGroup_basic = ` - resource "checkly_check_group" "test" { - name = "test" - activated = true - muted = false - concurrency = 3 - locations = [ - "us-east-1", - "eu-central-1", - ] - } -` - -const testCheckGroup_withApiDefaults = ` - resource "checkly_check_group" "test" { - name = "test" - activated = true - muted = false - concurrency = 3 - locations = [ - "eu-west-1", - "eu-west-2" - ] - api_check_defaults { - url = "http://api.example.com/" - } - } -` - -const testCheckGroup_full = ` - resource "checkly_check_group" "test" { - name = "test" - activated = true - muted = false - concurrency = 3 - double_check = true - use_global_alert_settings = false - locations = [ "us-east-1", "eu-central-1" ] - api_check_defaults { - url = "http://example.com/" - headers = { - X-Test = "foo" - } - query_parameters = { - query = "foo" - } - assertion { - source = "STATUS_CODE" - property = "" - comparison = "EQUALS" - target = "200" - } - basic_auth { - username = "user" - password = "pass" - } - } - environment_variables = { - FOO = "BAR" - } - alert_settings { - escalation_type = "RUN_BASED" - run_based_escalation { - failed_run_threshold = 1 - } - reminders { - amount = 2 - interval = 5 - } - parallel_run_failure_threshold { - enabled = false - percentage = 10 - } - } - local_setup_script = "setup-test" - local_teardown_script = "teardown-test" - } -` diff --git a/checkly/resource_check_test.go b/checkly/resource_check_test.go deleted file mode 100644 index f388f22..0000000 --- a/checkly/resource_check_test.go +++ /dev/null @@ -1,698 +0,0 @@ -package checkly - -import ( - "net/http" - "regexp" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - - "github.com/checkly/checkly-go-sdk" -) - -func TestAccCheckRequiredFields(t *testing.T) { - config := `resource "checkly_check" "test" {}` - accTestCase(t, []resource.TestStep{ - { - Config: config, - ExpectError: regexp.MustCompile(`The argument "type" is required, but no definition was found.`), - }, - { - Config: config, - ExpectError: regexp.MustCompile(`The argument "name" is required, but no definition was found.`), - }, - { - Config: config, - ExpectError: regexp.MustCompile(`The argument "activated" is required, but no definition was found.`), - }, - { - Config: config, - ExpectError: regexp.MustCompile(`The argument "frequency" is required, but no definition was found.`), - }, - }) -} - -func TestAccBrowserCheckInvalidInputs(t *testing.T) { - config := `resource "checkly_check" "test" { - name = 1 - type = "BROWSER" - activated = "invalid" - should_fail = "invalid" - double_check = "invalid" - use_global_alert_settings = "invalid" - locations = "invalid" - script = 4 - }` - accTestCase(t, []resource.TestStep{ - { - Config: config, - ExpectError: regexp.MustCompile(`Inappropriate value for attribute "activated"`), - }, - { - Config: config, - ExpectError: regexp.MustCompile(`The argument "frequency" is required`), - }, - { - Config: config, - ExpectError: regexp.MustCompile(`Inappropriate value for attribute "should_fail"`), - }, - { - Config: config, - ExpectError: regexp.MustCompile(`Inappropriate value for attribute "use_global_alert_settings"`), - }, - { - Config: config, - ExpectError: regexp.MustCompile(`Inappropriate value for attribute "double_check"`), - }, - { - Config: config, - ExpectError: regexp.MustCompile(`Inappropriate value for attribute "locations"`), - }, - }) -} - -func TestAccBrowserCheckMissingScript(t *testing.T) { - config := `resource "checkly_check" "test" { - type = "BROWSER" - activated = true - frequency = 10 - name = "browser check" - locations = [ "us-west-1" ] - }` - accTestCase(t, []resource.TestStep{ - { - Config: config, - ExpectError: regexp.MustCompile(`API error 1: unexpected response status 400`), - }, - }) -} - -func TestAccBrowserCheckBasic(t *testing.T) { - accTestCase(t, []resource.TestStep{ - { - Config: browserCheck_basic, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "checkly_check.test", - "name", - "Browser Check", - ), - resource.TestCheckResourceAttr( - "checkly_check.test", - "type", - "BROWSER", - ), - resource.TestCheckResourceAttr( - "checkly_check.test", - "activated", - "true", - ), - resource.TestCheckResourceAttr( - "checkly_check.test", - "script", - "console.log('test')", - ), - resource.TestCheckResourceAttr( - "checkly_check.test", - "locations.#", - "2", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "locations.*", - "us-east-1", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "locations.*", - "eu-central-1", - ), - resource.TestCheckResourceAttr( - "checkly_check.test", - "tags.#", - "2", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "tags.*", - "browser", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "tags.*", - "e2e", - ), - resource.TestCheckNoResourceAttr( - "checkly_check.test", - "request", - ), - ), - }, - }) -} - -func TestAccApiCheckBasic(t *testing.T) { - accTestCase(t, []resource.TestStep{ - { - Config: apiCheck_basic, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "checkly_check.test", - "name", - "API Check 1", - ), - resource.TestCheckResourceAttr( - "checkly_check.test", - "activated", - "true", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "locations.*", - "eu-central-1", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "locations.*", - "us-east-1", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "request.*.method", - "GET", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "request.*.url", - "https://api.checklyhq.com/public-stats", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "request.*.assertion.*.comparison", - "EQUALS", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "request.*.assertion.*.property", - "", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "request.*.assertion.*.source", - "STATUS_CODE", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "request.*.assertion.*.target", - "200", - ), - ), - }, - }) -} - -func TestAccMultiStepCheckRuntimeValidation(t *testing.T) { - unsupportedRuntime := `resource "checkly_check" "test" { - name = "test" - type = "MULTI_STEP" - activated = true - frequency = 5 - locations = ["eu-central-1"] - script = "console.log('test')" - runtime_id = "2023.02" - }` - noSpecifiedRuntime := `resource "checkly_check" "test" { - name = "test" - type = "MULTI_STEP" - activated = true - frequency = 5 - locations = ["eu-central-1"] - script = "console.log('test')" - }` - accTestCase(t, []resource.TestStep{ - { - Config: unsupportedRuntime, - ExpectError: regexp.MustCompile("Error: runtime 2023.02 does not support MULTI_STEP checks"), - }, - { - Config: noSpecifiedRuntime, - Check: resource.TestCheckNoResourceAttr( - "checkly_check.test", - "runtime_id", - ), - }, - }) -} - -func TestAccMultiStepCheckBasic(t *testing.T) { - accTestCase(t, []resource.TestStep{ - { - Config: multiStepCheck_basic, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "checkly_check.test", - "name", - "MultiStep Check", - ), - resource.TestCheckResourceAttr( - "checkly_check.test", - "type", - "MULTI_STEP", - ), - resource.TestCheckResourceAttr( - "checkly_check.test", - "runtime_id", - "2023.09", - ), - resource.TestCheckResourceAttr( - "checkly_check.test", - "activated", - "true", - ), - resource.TestCheckResourceAttr( - "checkly_check.test", - "script", - "console.log('test')", - ), - resource.TestCheckResourceAttr( - "checkly_check.test", - "locations.#", - "2", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "locations.*", - "us-east-1", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "locations.*", - "eu-central-1", - ), - resource.TestCheckResourceAttr( - "checkly_check.test", - "tags.#", - "2", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "tags.*", - "browser", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "tags.*", - "e2e", - ), - resource.TestCheckNoResourceAttr( - "checkly_check.test", - "request", - ), - ), - }, - }) -} - -func TestAccApiCheckFull(t *testing.T) { - accTestCase(t, []resource.TestStep{ - { - Config: apiCheck_full, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "checkly_check.test", - "degraded_response_time", - "15000", - ), - resource.TestCheckResourceAttr( - "checkly_check.test", - "max_response_time", - "30000", - ), - resource.TestCheckNoResourceAttr( - "checkly_check.test", - "environment_variables", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - `"locations.#"`, - "3", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - `"request.*.headers.X-CUSTOM-1"`, - "1", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "request.*.headers.X-CUSTOM-2", - "FOO", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "request.*.query_parameters.param1", - "123", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "request.*.query_parameters.param2", - "bar", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "request.*.basic_auth.*.username", - "user", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "request.*.basic_auth.*.password", - "pass", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "request.*.assertion.#", - "3", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "request.*.assertion.*.comparison", - "EQUALS", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "request.*.assertion.*.comparison", - "GREATER_THAN", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "request.*.assertion.*.target", - "200", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "request.*.assertion.*.target", - "no-cache", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "request.*.assertion.*.target", - "100", - ), - ), - }, - }) -} - -func TestAccApiCheckMore(t *testing.T) { - accTestCase(t, []resource.TestStep{ - { - Config: apiCheck_post, - Check: resource.ComposeTestCheckFunc( - testCheckResourceAttrExpr( - "checkly_check.test", - "request.*.method", - "POST", - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "request.*.body", - `{\"message\":\"hello checkly\",\"messageId\":1}`, - ), - testCheckResourceAttrExpr( - "checkly_check.test", - "request.*.body_type", - "JSON", - ), - ), - }, - { - Config: apiCheck_withEmptyBasicAuth, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "checkly_check.test", - "name", - "api check with empty basic_auth", - ), - ), - }, - }) -} - -var wantCheck = checkly.Check{ - Name: "My test check", - Type: checkly.TypeAPI, - Frequency: 1, - Activated: true, - Muted: false, - ShouldFail: false, - Locations: []string{"eu-west-1"}, - PrivateLocations: &[]string{}, - Script: "foo", - DegradedResponseTime: 15000, - MaxResponseTime: 30000, - EnvironmentVariables: []checkly.EnvironmentVariable{ - { - Key: "ENVTEST", - Value: "Hello world", - }, - }, - DoubleCheck: false, - Tags: []string{ - "foo", - "bar", - }, - SSLCheck: false, - LocalSetupScript: "bogus", - LocalTearDownScript: "bogus", - AlertSettings: checkly.AlertSettings{ - EscalationType: checkly.RunBased, - RunBasedEscalation: checkly.RunBasedEscalation{ - FailedRunThreshold: 1, - }, - Reminders: checkly.Reminders{ - Interval: 5, - }, - }, - UseGlobalAlertSettings: false, - Request: checkly.Request{ - Method: http.MethodGet, - URL: "http://example.com", - Headers: []checkly.KeyValue{ - { - Key: "X-Test", - Value: "foo", - }, - }, - QueryParameters: []checkly.KeyValue{ - { - Key: "query", - Value: "foo", - }, - }, - Assertions: []checkly.Assertion{ - { - Source: checkly.StatusCode, - Comparison: checkly.Equals, - Target: "200", - }, - }, - Body: "", - BodyType: "NONE", - BasicAuth: &checkly.BasicAuth{ - Username: "example", - Password: "pass", - }, - }, -} - -func TestEncodeDecodeResource(t *testing.T) { - res := resourceCheck() - data := res.TestResourceData() - wantCheck.AlertChannelSubscriptions = []checkly.AlertChannelSubscription{} - resourceDataFromCheck(&wantCheck, data) - got, err := checkFromResourceData(data) - if err != nil { - t.Fatal(err) - } - if !cmp.Equal(wantCheck, got) { - t.Error(cmp.Diff(wantCheck, got)) - } -} - -const browserCheck_basic = ` - resource "checkly_check" "test" { - name = "Browser Check" - type = "BROWSER" - activated = true - should_fail = false - frequency = 720 - double_check = true - use_global_alert_settings = true - locations = [ "us-east-1", "eu-central-1" ] - tags = [ "browser", "e2e" ] - script = "console.log('test')" - } -` -const multiStepCheck_basic = ` - resource "checkly_check" "test" { - name = "MultiStep Check" - type = "MULTI_STEP" - activated = true - should_fail = false - frequency = 720 - double_check = true - use_global_alert_settings = true - locations = [ "us-east-1", "eu-central-1" ] - tags = [ "api", "multi-step" ] - runtime_id = "2023.09" - script = "console.log('test')" - } -` - -const apiCheck_basic = ` - resource "checkly_check" "test" { - name = "API Check 1" - type = "API" - frequency = 60 - activated = true - muted = true - double_check = true - max_response_time = 18000 - locations = [ "us-east-1", "eu-central-1" ] - use_global_alert_settings = true - request { - method = "GET" - url = "https://api.checklyhq.com/public-stats" - assertion { - comparison = "EQUALS" - property = "" - source = "STATUS_CODE" - target = "200" - } - } - } -` - -const apiCheck_full = ` - resource "checkly_check" "test" { - name = "apiCheck_full" - type = "API" - frequency = 120 - activated = true - muted = true - double_check = true - degraded_response_time = 15000 - max_response_time = 30000 - environment_variables = null - locations = [ - "eu-central-1", - "us-east-1", - "ap-northeast-1" - ] - request { - method = "GET" - url = "https://api.checklyhq.com/public-stats" - follow_redirects = true - headers = { - X-CUSTOM-1 = 1 - X-CUSTOM-2 = "foo" - } - query_parameters = { - param1 = 123 - param2 = "bar" - } - basic_auth { - username = "user" - password = "pass" - } - assertion { - comparison = "EQUALS" - property = "" - source = "STATUS_CODE" - target = "200" - } - assertion { - comparison = "EQUALS" - property = "cache-control" - source = "HEADERS" - target = "no-cache" - } - assertion { - comparison = "GREATER_THAN" - property = "$.apiCheckResults" - source = "JSON_BODY" - target = "100" - } - } - - alert_settings { - escalation_type = "RUN_BASED" - reminders { - amount = 0 - interval = 5 - } - run_based_escalation { - failed_run_threshold = 1 - } - parallel_run_failure_threshold { - enabled = false - percentage = 10 - } - } - } -` - -const apiCheck_post = ` - resource "checkly_check" "test" { - name = "apiCheck_post" - type = "API" - activated = true - double_check = true - frequency = 720 - locations = [ "eu-central-1", "us-east-2" ] - max_response_time = 18000 - muted = true - environment_variables = null - request { - method = "POST" - url = "https://jsonplaceholder.typicode.com/posts" - headers = { - Content-type = "application/json; charset=UTF-8" - } - body = "{\"message\":\"hello checkly\",\"messageId\":1}" - body_type = "JSON" - } - use_global_alert_settings = true - } -` - -const apiCheck_withEmptyBasicAuth = ` - resource "checkly_check" "test" { - name = "api check with empty basic_auth" - type = "API" - activated = true - should_fail = false - frequency = 1 - degraded_response_time = 3000 - max_response_time = 6000 - tags = [ - "testing", - "bug" - ] - locations = [ "eu-central-1" ] - request { - follow_redirects = false - url = "https://api.checklyhq.com/public-stats" - basic_auth { - username = "" - password = "" - } - assertion { - source = "STATUS_CODE" - property = "" - comparison = "EQUALS" - target = "200" - } - } - } -` diff --git a/checkly/resource_dashboard.go b/checkly/resource_dashboard.go deleted file mode 100644 index 68679c2..0000000 --- a/checkly/resource_dashboard.go +++ /dev/null @@ -1,275 +0,0 @@ -package checkly - -import ( - "context" - "fmt" - "strings" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - checkly "github.com/checkly/checkly-go-sdk" -) - -func validateOptions(options []int) func(val interface{}, key string) (warns []string, errs []error) { - return func(val interface{}, key string) (warns []string, errs []error) { - v := val.(int) - valid := false - for _, i := range options { - if v == i { - valid = true - } - } - if !valid { - errs = append(errs, fmt.Errorf("%q must be one of %v, got: %d", key, options, v)) - } - return warns, errs - } -} - -func resourceDashboard() *schema.Resource { - return &schema.Resource{ - Create: resourceDashboardCreate, - Read: resourceDashboardRead, - Update: resourceDashboardUpdate, - Delete: resourceDashboardDelete, - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, - }, - Schema: map[string]*schema.Schema{ - "custom_url": { - Type: schema.TypeString, - Required: true, - Description: "A subdomain name under 'checklyhq.com'. Needs to be unique across all users.", - }, - "custom_domain": { - Type: schema.TypeString, - Optional: true, - Default: nil, - Description: "A custom user domain, e.g. 'status.example.com'. See the docs on updating your DNS and SSL usage.", - }, - "logo": { - Type: schema.TypeString, - Optional: true, - Default: "", - Description: "A URL pointing to an image file to use for the dashboard logo.", - }, - "favicon": { - Type: schema.TypeString, - Optional: true, - Default: "", - Description: "A URL pointing to an image file to use as browser favicon.", - }, - "link": { - Type: schema.TypeString, - Optional: true, - Default: "", - Description: "A link to for the dashboard logo.", - }, - "description": { - Type: schema.TypeString, - Optional: true, - Default: "", - Description: "HTML description for the dashboard.", - }, - "header": { - Type: schema.TypeString, - Optional: true, - Default: "", - Description: "A piece of text displayed at the top of your dashboard.", - }, - "width": { - Type: schema.TypeString, - Optional: true, - Default: "FULL", - ValidateFunc: func(value interface{}, key string) (warns []string, errs []error) { - full := "FULL" - px960 := "960PX" - v := value.(string) - if v != full && v != px960 { - errs = append(errs, fmt.Errorf("%q must %s and %s, got: %s", key, full, px960, v)) - } - return warns, errs - }, - Description: "Determines whether to use the full screen or focus in the center. Possible values `FULL` and `960PX`.", - }, - "refresh_rate": { - Type: schema.TypeInt, - Optional: true, - Default: 60, - ValidateFunc: validateOptions([]int{60, 300, 600}), - Description: "How often to refresh the dashboard in seconds. Possible values `60`, '300' and `600`.", - }, - "paginate": { - Type: schema.TypeBool, - Optional: true, - Default: true, - Description: "Determines if pagination is on or off.", - }, - "checks_per_page": { - Type: schema.TypeInt, - Optional: true, - Default: 15, - Description: "Determines how many checks to show per page.", - }, - "pagination_rate": { - Type: schema.TypeInt, - Optional: true, - Default: 60, - ValidateFunc: validateOptions([]int{30, 60, 300}), - Description: "How often to trigger pagination in seconds. Possible values `30`, `60` and `300`.", - }, - "tags": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - Description: "A list of one or more tags that filter which checks to display on the dashboard.", - }, - "hide_tags": { - Type: schema.TypeBool, - Optional: true, - Default: false, - Description: "Show or hide the tags on the dashboard.", - }, - "use_tags_and_operator": { - Type: schema.TypeBool, - Optional: true, - Default: false, - Description: "Set when to use AND operator for fetching dashboard tags.", - }, - "is_private": { - Type: schema.TypeBool, - Optional: true, - Default: false, - Description: "Set your dashboard as private and generate key.", - }, - // moving to TypeString here https://github.com/hashicorp/terraform-plugin-sdk/issues/792 - "key": { - Type: schema.TypeString, - Computed: true, - Sensitive: true, - Description: "The access key when the dashboard is private.", - }, - }, - } -} - -func dashboardFromResourceData(d *schema.ResourceData) (checkly.Dashboard, error) { - a := checkly.Dashboard{ - CustomDomain: d.Get("custom_domain").(string), - CustomUrl: d.Get("custom_url").(string), - Logo: d.Get("logo").(string), - Favicon: d.Get("favicon").(string), - Link: d.Get("link").(string), - Description: d.Get("description").(string), - Header: d.Get("header").(string), - RefreshRate: d.Get("refresh_rate").(int), - Paginate: d.Get("paginate").(bool), - ChecksPerPage: d.Get("checks_per_page").(int), - PaginationRate: d.Get("pagination_rate").(int), - HideTags: d.Get("hide_tags").(bool), - Width: d.Get("width").(string), - UseTagsAndOperator: d.Get("use_tags_and_operator").(bool), - IsPrivate: d.Get("is_private").(bool), - Tags: stringsFromSet(d.Get("tags").(*schema.Set)), - } - - fmt.Printf("%v", a) - - return a, nil -} - -func resourceDataFromDashboard(s *checkly.Dashboard, d *schema.ResourceData) error { - d.Set("custom_domain", s.CustomDomain) - d.Set("custom_url", s.CustomUrl) - d.Set("logo", s.Logo) - d.Set("favicon", s.Favicon) - d.Set("link", s.Link) - d.Set("description", s.Description) - d.Set("header", s.Header) - d.Set("refresh_rate", s.RefreshRate) - d.Set("paginate", s.Paginate) - d.Set("checks_per_page", s.ChecksPerPage) - d.Set("pagination_rate", s.PaginationRate) - d.Set("hide_tags", s.HideTags) - d.Set("tags", s.Tags) - d.Set("width", s.Width) - d.Set("use_tags_and_operator", s.UseTagsAndOperator) - d.Set("is_private", s.IsPrivate) - - // if the dashboard is private, we either do nothing - // or set the key to a new value if there is any - if s.IsPrivate { - if len(s.Keys) > 0 { - d.Set("key", s.Keys[0].RawKey) - } - } else { - // if the dashboard is public, remove the key - d.Set("key", nil) - } - - return nil -} - -func resourceDashboardCreate(d *schema.ResourceData, client interface{}) error { - dashboard, err := dashboardFromResourceData(d) - if err != nil { - return fmt.Errorf("resourceDashboardCreate: translation error: %w", err) - } - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - result, err := client.(checkly.Client).CreateDashboard(ctx, dashboard) - - if err != nil { - return fmt.Errorf("CreateDashboard: API error: %w", err) - } - - d.SetId(result.DashboardID) - - // we cannot take the detour through resourceDashboardRead since - // we would not get the keys back from an additional GET call - return resourceDataFromDashboard(result, d) -} - -func resourceDashboardUpdate(d *schema.ResourceData, client interface{}) error { - dashboard, err := dashboardFromResourceData(d) - if err != nil { - return fmt.Errorf("resourceDashboardUpdate: translation error: %w", err) - } - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - result, err := client.(checkly.Client).UpdateDashboard(ctx, d.Id(), dashboard) - if err != nil { - return fmt.Errorf("resourceDashboardUpdate: API error: %w", err) - } - d.SetId(result.DashboardID) - - // we cannot take the detour through resourceDashboardRead since - // we would not get the keys back from an additional GET call - return resourceDataFromDashboard(result, d) -} - -func resourceDashboardDelete(d *schema.ResourceData, client interface{}) error { - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - err := client.(checkly.Client).DeleteDashboard(ctx, d.Id()) - if err != nil { - return fmt.Errorf("resourceDashboardDelete: API error: %w", err) - } - return nil -} - -func resourceDashboardRead(d *schema.ResourceData, client interface{}) error { - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - dashboard, err := client.(checkly.Client).GetDashboard(ctx, d.Id()) - defer cancel() - if err != nil { - if strings.Contains(err.Error(), "404") { - d.SetId("") - return nil - } - return fmt.Errorf("resourceDashboardRead: API error: %w", err) - } - return resourceDataFromDashboard(dashboard, d) -} diff --git a/checkly/resource_environment_variable.go b/checkly/resource_environment_variable.go deleted file mode 100644 index fb55897..0000000 --- a/checkly/resource_environment_variable.go +++ /dev/null @@ -1,118 +0,0 @@ -package checkly - -import ( - "context" - "fmt" - "strings" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - checkly "github.com/checkly/checkly-go-sdk" -) - -func resourceEnvironmentVariable() *schema.Resource { - return &schema.Resource{ - Create: resourceEnvironmentVariableCreate, - Read: resourceEnvironmentVariableRead, - Update: resourceEnvironmentVariableUpdate, - Delete: resourceEnvironmentVariableDelete, - Importer: &schema.ResourceImporter{ - State: schema.ImportStatePassthrough, - }, - Schema: map[string]*schema.Schema{ - "key": { - Type: schema.TypeString, - Required: true, - }, - "value": { - Type: schema.TypeString, - Required: true, - }, - "locked": { - Type: schema.TypeBool, - Optional: true, - Default: false, - }, - "secret": { - Type: schema.TypeBool, - Optional: true, - Default: false, - }, - }, - } -} - -func resourceEnvironmentVariableCreate(d *schema.ResourceData, client interface{}) error { - envVar, err := environmentVariableFromResourceData(d) - if err != nil { - return fmt.Errorf("resourceEnvironmentVariableCreate: translation error: %w", err) - } - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - _, err = client.(checkly.Client).CreateEnvironmentVariable(ctx, envVar) - if err != nil { - return fmt.Errorf("CreateEnvironmentVariable: API error: %w", err) - } - d.SetId(envVar.Key) - return resourceEnvironmentVariableRead(d, client) -} - -func environmentVariableFromResourceData(d *schema.ResourceData) (checkly.EnvironmentVariable, error) { - return checkly.EnvironmentVariable{ - Key: d.Get("key").(string), - Value: d.Get("value").(string), - Locked: d.Get("locked").(bool), - Secret: d.Get("secret").(bool), - }, nil -} - -func resourceDataFromEnvironmentVariable(s *checkly.EnvironmentVariable, d *schema.ResourceData) error { - d.Set("key", s.Key) - if !s.Secret { - d.Set("value", s.Value) - } - d.Set("locked", s.Locked) - d.Set("secret", s.Secret) - return nil -} - -func resourceEnvironmentVariableRead(d *schema.ResourceData, client interface{}) error { - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - envVar, err := client.(checkly.Client).GetEnvironmentVariable(ctx, d.Id()) - if err != nil { - if strings.Contains(err.Error(), "404") { - //if resource is deleted remotely, then mark it as - //successfully gone by unsetting it's ID - d.SetId("") - return nil - } - return fmt.Errorf("resourceEnvironmentVariableRead: API error: %w", err) - } - return resourceDataFromEnvironmentVariable(envVar, d) -} - -func resourceEnvironmentVariableUpdate(d *schema.ResourceData, client interface{}) error { - envVar, err := environmentVariableFromResourceData(d) - if err != nil { - return fmt.Errorf("resourceEnvironmentVariableUpdate: translation error: %w", err) - } - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - _, err = client.(checkly.Client).UpdateEnvironmentVariable(ctx, d.Id(), envVar) - if err != nil { - return fmt.Errorf("resourceEnvironmentVariableUpdate: API error: %w", err) - } - - return resourceEnvironmentVariableRead(d, client) -} - -func resourceEnvironmentVariableDelete(d *schema.ResourceData, client interface{}) error { - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - err := client.(checkly.Client).DeleteEnvironmentVariable(ctx, d.Id()) - if err != nil { - return fmt.Errorf("resourceEnvironmentVariableDelete: API error: %w", err) - } - return nil -} diff --git a/checkly/resource_environment_variable_test.go b/checkly/resource_environment_variable_test.go deleted file mode 100644 index 09fbccf..0000000 --- a/checkly/resource_environment_variable_test.go +++ /dev/null @@ -1,58 +0,0 @@ -package checkly - -import ( - "regexp" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccEnvVarCheckRequiredFields(t *testing.T) { - config := `resource "checkly_environment_variable" "test" {}` - accTestCase(t, []resource.TestStep{ - { - Config: config, - ExpectError: regexp.MustCompile(`The argument "key" is required`), - }, - { - Config: config, - ExpectError: regexp.MustCompile(`The argument "value" is required`), - }, - }) -} - -func TestAccEnvVarSuccess(t *testing.T) { - config := `resource "checkly_environment_variable" "test" { - key = "API_URL" - value = "https://api.checklyhq.com" - }` - accTestCase(t, []resource.TestStep{ - { - Config: config, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "checkly_environment_variable.test", - "key", - "API_URL", - ), - resource.TestCheckResourceAttr( - "checkly_environment_variable.test", - "value", - "https://api.checklyhq.com", - ), - ), - }, - }) -} - -func TestAccSecretEnvVarSuccess(t *testing.T) { - accTestCase(t, []resource.TestStep{ - { - Config: `resource "checkly_environment_variable" "test" { - key = "SECRET" - value = "https://api.checklyhq.com" - secret = true - }`, - }, - }) -} diff --git a/checkly/resource_heartbeat.go b/checkly/resource_heartbeat.go deleted file mode 100644 index 3b2fa0b..0000000 --- a/checkly/resource_heartbeat.go +++ /dev/null @@ -1,428 +0,0 @@ -package checkly - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "sort" - "strings" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - "github.com/checkly/checkly-go-sdk" -) - -func resourceHeartbeat() *schema.Resource { - return &schema.Resource{ - Create: resourceHeartbeatCreate, - Read: resourceHeartbeatRead, - Update: resourceHeartbeatUpdate, - Delete: resourceHeartbeatDelete, - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, - }, - Description: "Heartbeats allows you to monitor your cron jobs and set up alerting, so you get a notification when things break or slow down.", - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the check.", - }, - "activated": { - Type: schema.TypeBool, - Required: true, - Description: "Determines if the check is running or not. Possible values `true`, and `false`.", - }, - "muted": { - Type: schema.TypeBool, - Optional: true, - Description: "Determines if any notifications will be sent out when a check fails/degrades/recovers.", - }, - "tags": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - Description: "A list of tags for organizing and filtering checks.", - }, - "alert_settings": { - Type: schema.TypeList, - Optional: true, - Computed: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "escalation_type": { - Type: schema.TypeString, - Optional: true, - Description: "Determines what type of escalation to use. Possible values are `RUN_BASED` or `TIME_BASED`.", - }, - "run_based_escalation": { - Type: schema.TypeList, - Optional: true, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "failed_run_threshold": { - Type: schema.TypeInt, - Optional: true, - Description: "After how many failed consecutive check runs an alert notification should be sent. Possible values are between 1 and 5. (Default `1`).", - }, - }, - }, - }, - "time_based_escalation": { - Type: schema.TypeList, - Optional: true, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "minutes_failing_threshold": { - Type: schema.TypeInt, - Optional: true, - Description: "After how many minutes after a check starts failing an alert should be sent. Possible values are `5`, `10`, `15`, and `30`. (Default `5`).", - }, - }, - }, - }, - "reminders": { - Type: schema.TypeList, - Optional: true, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "amount": { - Type: schema.TypeInt, - Optional: true, - Description: "How many reminders to send out after the initial alert notification. Possible values are `0`, `1`, `2`, `3`, `4`, `5`, and `100000`", - }, - "interval": { - Type: schema.TypeInt, - Optional: true, - Default: 5, - Description: "Possible values are `5`, `10`, `15`, and `30`. (Default `5`).", - }, - }, - }, - }, - "parallel_run_failure_threshold": { - Type: schema.TypeList, - Optional: true, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "enabled": { - Type: schema.TypeBool, - Optional: true, - Default: false, - Description: "Applicable only for checks scheduled in parallel in multiple locations.", - }, - "percentage": { - Type: schema.TypeInt, - Optional: true, - Default: 10, - Description: "Possible values are `10`, `20`, `30`, `40`, `50`, `60`, `70`, `80`, `100`, and `100`. (Default `10`).", - }, - }, - }, - }, - "ssl_certificates": { - Type: schema.TypeSet, - Optional: true, - Deprecated: "This property is deprecated and it's ignored by the Checkly Public API. It will be removed in a future version.", - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "enabled": { - Type: schema.TypeBool, - Optional: true, - Description: "Determines if alert notifications should be sent for expiring SSL certificates. Possible values `true`, and `false`. (Default `false`).", - }, - "alert_threshold": { - Type: schema.TypeInt, - Optional: true, - ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) { - v := val.(int) - valid := false - validFreqs := []int{3, 7, 14, 30} - for _, i := range validFreqs { - if v == i { - valid = true - } - } - if !valid { - errs = append(errs, fmt.Errorf("%q must be one of %v, got: %d", key, validFreqs, v)) - } - return warns, errs - }, - Description: "How long before SSL certificate expiry to send alerts. Possible values `3`, `7`, `14`, `30`. (Default `3`).", - }, - }, - Description: "At what interval the reminders should be sent.", - }, - }, - }, - }, - }, - "use_global_alert_settings": { - Type: schema.TypeBool, - Optional: true, - Description: "When true, the account level alert settings will be used, not the alert setting defined on this check.", - }, - "heartbeat": { - Type: schema.TypeSet, - Required: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "period": { - Type: schema.TypeInt, - Required: true, - Description: "How often you expect a ping to the ping URL.", - }, - "period_unit": { - Type: schema.TypeString, - Required: true, - ValidateFunc: func(value interface{}, key string) (warns []string, errs []error) { - v := value.(string) - isValid := false - options := []string{"seconds", "minutes", "hours", "days"} - for _, option := range options { - if v == option { - isValid = true - } - } - if !isValid { - errs = append(errs, fmt.Errorf("%q must be one of %v, got %s", key, options, v)) - } - return warns, errs - }, - Description: "Possible values `seconds`, `minutes`, `hours` and `days`.", - }, - "grace": { - Type: schema.TypeInt, - Required: true, - Description: "How long Checkly should wait before triggering any alerts when a ping does not arrive within the set period.", - }, - "grace_unit": { - Type: schema.TypeString, - Required: true, - ValidateFunc: func(value interface{}, key string) (warns []string, errs []error) { - v := value.(string) - isValid := false - options := []string{"seconds", "minutes", "hours", "days"} - for _, option := range options { - if v == option { - isValid = true - } - } - if !isValid { - errs = append(errs, fmt.Errorf("%q must be one of %v, got %s", key, options, v)) - } - return warns, errs - }, - Description: "Possible values `seconds`, `minutes`, `hours` and `days`.", - }, - "ping_token": { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "Custom token to generate your ping URL. Checkly will expect a ping to `https://ping.checklyhq.com/[PING_TOKEN]`.", - }, - }, - }, - }, - "alert_channel_subscription": { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "channel_id": { - Type: schema.TypeInt, - Required: true, - }, - "activated": { - Type: schema.TypeBool, - Required: true, - }, - }, - }, - }, - }, - } -} - -func resourceHeartbeatCreate(d *schema.ResourceData, client interface{}) error { - check, err := heartbeatCheckFromResourceData(d) - - if err != nil { - return fmt.Errorf("translation error: %w", err) - } - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - newCheck, err := client.(checkly.Client).CreateHeartbeat(ctx, check) - - if err != nil { - checkJSON, _ := json.Marshal(check) - return fmt.Errorf("API error 1: %w, Check: %s", err, string(checkJSON)) - } - d.SetId(newCheck.ID) - return resourceHeartbeatRead(d, client) -} - -func resourceHeartbeatRead(d *schema.ResourceData, client interface{}) error { - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - check, err := client.(checkly.Client).GetHeartbeatCheck(ctx, d.Id()) - if err != nil { - if strings.Contains(err.Error(), "404") { - //if resource is deleted remotely, then mark it as - //successfully gone by unsetting it's ID - d.SetId("") - return nil - } - return fmt.Errorf("API error 2: %w", err) - } - return resourceDataFromHeartbeat(check, d) -} - -func resourceHeartbeatUpdate(d *schema.ResourceData, client interface{}) error { - check, err := heartbeatCheckFromResourceData(d) - - if err != nil { - return fmt.Errorf("translation error: %w", err) - } - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - _, err = client.(checkly.Client).UpdateHeartbeat(ctx, check.ID, check) - if err != nil { - checkJSON, _ := json.Marshal(check) - return fmt.Errorf("API error 3: Couldn't update check, Error: %w, \nCheck: %s", err, checkJSON) - } - d.SetId(check.ID) - return resourceHeartbeatRead(d, client) -} - -func resourceHeartbeatDelete(d *schema.ResourceData, client interface{}) error { - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - if err := client.(checkly.Client).Delete(ctx, d.Id()); err != nil { - return fmt.Errorf("API error 4: Couldn't delete Check %s, Error: %w", d.Id(), err) - } - return nil -} - -func heartbeatCheckFromResourceData(d *schema.ResourceData) (checkly.HeartbeatCheck, error) { - check := checkly.HeartbeatCheck{ - ID: d.Id(), - Name: d.Get("name").(string), - Activated: d.Get("activated").(bool), - Muted: d.Get("muted").(bool), - Tags: stringsFromSet(d.Get("tags").(*schema.Set)), - AlertSettings: alertSettingsFromSet(d.Get("alert_settings").([]interface{})), - UseGlobalAlertSettings: d.Get("use_global_alert_settings").(bool), - AlertChannelSubscriptions: alertChannelSubscriptionsFromSet(d.Get("alert_channel_subscription").([]interface{})), - } - - // this will prevent subsequent apply from causing a tf config change in browser checks - check.Heartbeat = heartbeatFromSet(d.Get("heartbeat").(*schema.Set)) - - // Period / Grace validation - periodDaysInHours := 0 - periodHours := 0 - periodMinutes := 0 - periodSseconds := 0 - graceDaysInHours := 0 - graceHours := 0 - graceMinutes := 0 - graceSseconds := 0 - - if check.Heartbeat.PeriodUnit == "days" { - periodDaysInHours = check.Heartbeat.Period * 24 - } else if check.Heartbeat.PeriodUnit == "hours" { - periodHours = check.Heartbeat.Period - } else if check.Heartbeat.PeriodUnit == "minutes" { - periodMinutes = check.Heartbeat.Period - } else { - periodSseconds = check.Heartbeat.Period - } - - if check.Heartbeat.GraceUnit == "days" { - graceDaysInHours = check.Heartbeat.Grace * 24 - } else if check.Heartbeat.GraceUnit == "hours" { - graceHours = check.Heartbeat.Grace - } else if check.Heartbeat.GraceUnit == "minutes" { - graceMinutes = check.Heartbeat.Grace - } else { - graceSseconds = check.Heartbeat.Grace - } - - now := time.Now().Local() - addedTimePeriod := time.Now().Local().Add( - time.Hour*time.Duration(periodDaysInHours+periodHours) + - time.Minute*time.Duration(periodMinutes) + - time.Second*time.Duration(periodSseconds)) - addedTimeGrace := time.Now().Local().Add( - time.Hour*time.Duration(graceDaysInHours+graceHours) + - time.Minute*time.Duration(graceMinutes) + - time.Second*time.Duration(graceSseconds)) - - if addedTimePeriod.Sub(now).Hours()/float64(24) > 365 || addedTimePeriod.Sub(now).Seconds() < 30 { - return check, errors.New(fmt.Sprintf("period must be between 30 seconds and 365 days")) - } - - if addedTimeGrace.Sub(now).Hours()/float64(24) > 365 { - return check, errors.New("grace must be less than 365 days") - } - - return check, nil -} - -func resourceDataFromHeartbeat(c *checkly.HeartbeatCheck, d *schema.ResourceData) error { - d.Set("name", c.Name) - d.Set("activated", c.Activated) - d.Set("muted", c.Muted) - - sort.Strings(c.Tags) - d.Set("tags", c.Tags) - if err := d.Set("alert_settings", setFromAlertSettings(c.AlertSettings)); err != nil { - return fmt.Errorf("error setting alert settings for resource %s: %w", d.Id(), err) - } - d.Set("use_global_alert_settings", c.UseGlobalAlertSettings) - - err := d.Set("heartbeat", setFromHeartbeat(c.Heartbeat)) - if err != nil { - return fmt.Errorf("error setting heartbeat for resource %s: %w %v", d.Id(), err, c.Heartbeat) - } - - d.Set("alert_channel_subscription", c.AlertChannelSubscriptions) - d.SetId(d.Id()) - - return nil -} - -func setFromHeartbeat(r checkly.Heartbeat) []tfMap { - s := tfMap{} - s["period"] = r.Period - s["period_unit"] = r.PeriodUnit - s["grace_unit"] = r.GraceUnit - s["grace"] = r.Grace - s["ping_token"] = r.PingToken - return []tfMap{s} -} - -func heartbeatFromSet(s *schema.Set) checkly.Heartbeat { - if s.Len() == 0 { - return checkly.Heartbeat{} - } - res := s.List()[0].(tfMap) - return checkly.Heartbeat{ - Period: res["period"].(int), - PeriodUnit: res["period_unit"].(string), - Grace: res["grace"].(int), - GraceUnit: res["grace_unit"].(string), - PingToken: res["ping_token"].(string), - } -} diff --git a/checkly/resource_heartbeat_test.go b/checkly/resource_heartbeat_test.go deleted file mode 100644 index 3d11882..0000000 --- a/checkly/resource_heartbeat_test.go +++ /dev/null @@ -1,192 +0,0 @@ -package checkly - -import ( - "regexp" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccHeartbeatRequiredFields(t *testing.T) { - config := `resource "checkly_heartbeat" "test" {}` - accTestCase(t, []resource.TestStep{ - { - Config: config, - ExpectError: regexp.MustCompile(`The argument "name" is required, but no definition was found.`), - }, - { - Config: config, - ExpectError: regexp.MustCompile(`The argument "activated" is required, but no definition was found.`), - }, - }) -} - -func TestAccHeartbeatCheckInvalidInputs(t *testing.T) { - config := `resource "checkly_check" "test" { - name = 1 - activated = "invalid" - use_global_alert_settings = "invalid" - }` - accTestCase(t, []resource.TestStep{ - { - Config: config, - ExpectError: regexp.MustCompile(`Inappropriate value for attribute "activated"`), - }, - { - Config: config, - ExpectError: regexp.MustCompile(`Inappropriate value for attribute "use_global_alert_settings"`), - }, - }) -} - -func TestAccHeartbeatCheckMissingHeartbeatBlock(t *testing.T) { - config := `resource "checkly_heartbeat" "test" { - activated = true - name = "heartbeat check" - }` - accTestCase(t, []resource.TestStep{ - { - Config: config, - ExpectError: regexp.MustCompile(`At least 1 "heartbeat" blocks are required.`), - }, - }) -} - -func TestAccHeartbeatCheckMissingHeartbeatFields(t *testing.T) { - config := `resource "checkly_heartbeat" "test" { - activated = true - name = "heartbeat check" - heartbeat { - - } - }` - accTestCase(t, []resource.TestStep{ - { - Config: config, - ExpectError: regexp.MustCompile(`The argument "grace" is required, but no definition was found.`), - }, - { - Config: config, - ExpectError: regexp.MustCompile(`The argument "grace_unit" is required, but no definition was found.`), - }, - { - Config: config, - ExpectError: regexp.MustCompile(`The argument "period" is required, but no definition was found.`), - }, - { - Config: config, - ExpectError: regexp.MustCompile(`The argument "period_unit" is required, but no definition was found.`), - }, - }) -} - -func TestAccHeartbeatCheckPeriodTooBig(t *testing.T) { - config := `resource "checkly_heartbeat" "test" { - activated = true - name = "heartbeat check" - heartbeat { - period = 366 - period_unit = "days" - grace = 0 - grace_unit = "seconds" - } - }` - accTestCase(t, []resource.TestStep{ - { - Config: config, - ExpectError: regexp.MustCompile(`translation error: period must be between 30 seconds and 365 days`), - }, - }) -} - -func TestAccHeartbeatCheckPeriodTooSmall(t *testing.T) { - config := `resource "checkly_heartbeat" "test" { - activated = true - name = "heartbeat check" - heartbeat { - period = 5 - period_unit = "seconds" - grace = 0 - grace_unit = "seconds" - } - }` - accTestCase(t, []resource.TestStep{ - { - Config: config, - ExpectError: regexp.MustCompile(`translation error: period must be between 30 seconds and 365 days`), - }, - }) -} - -func TestAccHeartbeatCheckInvalidPeriodUnit(t *testing.T) { - config := `resource "checkly_heartbeat" "test" { - activated = true - name = "heartbeat check" - heartbeat { - period = 5 - period_unit = "lightyear" - grace = 0 - grace_unit = "seconds" - } - }` - accTestCase(t, []resource.TestStep{ - { - Config: config, - ExpectError: regexp.MustCompile(`"heartbeat\.0\.period_unit" must be one of \[seconds minutes hours days\], got lightyear`), - }, - }) -} - -func TestAccHeartbeatCheckInvalidGraceUnit(t *testing.T) { - config := `resource "checkly_heartbeat" "test" { - activated = true - name = "heartbeat check" - heartbeat { - period = 5 - period_unit = "days" - grace = 0 - grace_unit = "lightyear" - } - }` - accTestCase(t, []resource.TestStep{ - { - Config: config, - ExpectError: regexp.MustCompile(`"heartbeat\.0\.grace_unit" must be one of \[seconds minutes hours days\], got lightyear`), - }, - }) -} - -func TestAccHeartbeatCheckCreate(t *testing.T) { - config := `resource "checkly_heartbeat" "test" { - activated = true - name = "heartbeat check" - heartbeat { - period = 5 - period_unit = "days" - grace = 0 - grace_unit = "seconds" - } - }` - accTestCase(t, []resource.TestStep{ - { - Config: config, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "checkly_heartbeat.test", - "name", - "heartbeat check", - ), - testCheckResourceAttrExpr( - "checkly_heartbeat.test", - "heartbeat.*.period", - "5", - ), - testCheckResourceAttrExpr( - "checkly_heartbeat.test", - "heartbeat.*.period_unit", - "days", - ), - ), - }, - }) -} diff --git a/checkly/resource_maintenance_window.go b/checkly/resource_maintenance_window.go deleted file mode 100644 index b8f5a32..0000000 --- a/checkly/resource_maintenance_window.go +++ /dev/null @@ -1,183 +0,0 @@ -package checkly - -import ( - "context" - "fmt" - "strconv" - "strings" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - checkly "github.com/checkly/checkly-go-sdk" -) - -func resourceMaintenanceWindow() *schema.Resource { - return &schema.Resource{ - Create: resourceMaintenanceWindowCreate, - Read: resourceMaintenanceWindowRead, - Update: resourceMaintenanceWindowUpdate, - Delete: resourceMaintenanceWindowDelete, - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, - }, - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "The maintenance window name.", - }, - "starts_at": { - Type: schema.TypeString, - Required: true, - Description: "The start date of the maintenance window.", - }, - "ends_at": { - Type: schema.TypeString, - Required: true, - Description: "The end date of the maintenance window.", - }, - "repeat_unit": { - Type: schema.TypeString, - Optional: true, - Default: nil, - ValidateFunc: func(value interface{}, key string) (warns []string, errs []error) { - v := value.(string) - isValid := false - options := []string{"DAY", "WEEK", "MONTH"} - for _, option := range options { - if v == option { - isValid = true - } - } - if !isValid { - errs = append(errs, fmt.Errorf("%q must be one of %v, got %s", key, options, v)) - } - return warns, errs - }, - Description: "The repeat cadence for the maintenance window. Possible values `DAY`, `WEEK` and `MONTH`.", - }, - "repeat_interval": { - Type: schema.TypeInt, - Optional: true, - Default: nil, - Description: "The repeat interval of the maintenance window from the first occurrence.", - }, - "repeat_ends_at": { - Type: schema.TypeString, - Optional: true, - Default: nil, - Description: "The date on which the maintenance window should stop repeating.", - }, - "tags": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - DefaultFunc: func() (interface{}, error) { - return []tfMap{}, nil - }, - Description: "The names of the checks and groups maintenance window should apply to.", - }, - }, - } -} - -func maintenanceWindowsFromResourceData(d *schema.ResourceData) (checkly.MaintenanceWindow, error) { - ID, err := strconv.ParseInt(d.Id(), 10, 64) - if err != nil { - if d.Id() != "" { - return checkly.MaintenanceWindow{}, err - } - ID = 0 - } - a := checkly.MaintenanceWindow{ - ID: ID, - Name: d.Get("name").(string), - StartsAt: d.Get("starts_at").(string), - EndsAt: d.Get("ends_at").(string), - RepeatUnit: d.Get("repeat_unit").(string), - RepeatEndsAt: d.Get("repeat_ends_at").(string), - RepeatInterval: d.Get("repeat_interval").(int), - Tags: stringsFromSet(d.Get("tags").(*schema.Set)), - } - - fmt.Printf("%v", a) - - return a, nil -} - -func resourceDataFromMaintenanceWindows(s *checkly.MaintenanceWindow, d *schema.ResourceData) error { - d.Set("name", s.Name) - d.Set("starts_at", s.StartsAt) - d.Set("ends_at", s.EndsAt) - d.Set("repeat_unit", s.RepeatUnit) - d.Set("repeat_ends_at", s.RepeatEndsAt) - d.Set("repeat_interval", s.RepeatInterval) - d.Set("tags", s.Tags) - return nil -} - -func resourceMaintenanceWindowCreate(d *schema.ResourceData, client interface{}) error { - mw, err := maintenanceWindowsFromResourceData(d) - if err != nil { - return fmt.Errorf("resourceMaintenanceWindowCreate: translation error: %w", err) - } - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - result, err := client.(checkly.Client).CreateMaintenanceWindow(ctx, mw) - - if err != nil { - return fmt.Errorf("CreateMaintenanceWindows: API error: %w", err) - } - - d.SetId(fmt.Sprintf("%d", result.ID)) - return resourceMaintenanceWindowRead(d, client) -} - -func resourceMaintenanceWindowUpdate(d *schema.ResourceData, client interface{}) error { - mw, err := maintenanceWindowsFromResourceData(d) - if err != nil { - return fmt.Errorf("resourceMaintenanceWindowUpdate: translation error: %w", err) - } - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - _, err = client.(checkly.Client).UpdateMaintenanceWindow(ctx, mw.ID, mw) - if err != nil { - return fmt.Errorf("resourceMaintenanceWindowUpdate: API error: %w", err) - } - d.SetId(fmt.Sprintf("%d", mw.ID)) - return resourceMaintenanceWindowRead(d, client) -} - -func resourceMaintenanceWindowDelete(d *schema.ResourceData, client interface{}) error { - ID, err := strconv.ParseInt(d.Id(), 10, 64) - if err != nil { - return fmt.Errorf("resourceMaintenanceWindowDelete: ID %s is not numeric: %w", d.Id(), err) - } - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - err = client.(checkly.Client).DeleteMaintenanceWindow(ctx, ID) - if err != nil { - return fmt.Errorf("resourceMaintenanceWindowDelete: API error: %w", err) - } - return nil -} - -func resourceMaintenanceWindowRead(d *schema.ResourceData, client interface{}) error { - ID, err := strconv.ParseInt(d.Id(), 10, 64) - if err != nil { - return fmt.Errorf("resourceMaintenanceWindowRead: ID %s is not numeric: %w", d.Id(), err) - } - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - mw, err := client.(checkly.Client).GetMaintenanceWindow(ctx, ID) - defer cancel() - if err != nil { - if strings.Contains(err.Error(), "404") { - d.SetId("") - return nil - } - return fmt.Errorf("resourceMaintenanceWindowRead: API error: %w", err) - } - return resourceDataFromMaintenanceWindows(mw, d) -} diff --git a/checkly/resource_private_locations.go b/checkly/resource_private_locations.go deleted file mode 100644 index d0e3f37..0000000 --- a/checkly/resource_private_locations.go +++ /dev/null @@ -1,123 +0,0 @@ -package checkly - -import ( - "context" - "fmt" - "strings" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - checkly "github.com/checkly/checkly-go-sdk" -) - -func resourcePrivateLocation() *schema.Resource { - return &schema.Resource{ - Create: resourcePrivateLocationCreate, - Read: resourcePrivateLocationRead, - Update: resourcePrivateLocationUpdate, - Delete: resourcePrivateLocationDelete, - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, - }, - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "The private location name.", - }, - "slug_name": { - Type: schema.TypeString, - Required: true, - Description: "Valid slug name.", - }, - "icon": { - Type: schema.TypeString, - Optional: true, - Default: "location", - Description: "Icon assigned to the private location.", - }, - "keys": { - Type: schema.TypeSet, - Computed: true, - Sensitive: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - Description: "Private location API keys.", - }, - }, - } -} - -func privateLocationFromResourceData(d *schema.ResourceData) (checkly.PrivateLocation, error) { - return checkly.PrivateLocation{ - Name: d.Get("name").(string), - SlugName: d.Get("slug_name").(string), - Icon: d.Get("icon").(string), - }, nil -} - -func resourcePrivateLocationCreate(d *schema.ResourceData, client interface{}) error { - pl, err := privateLocationFromResourceData(d) - if err != nil { - return fmt.Errorf("resourcePrivateLocationCreate: translation error: %w", err) - } - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - result, err := client.(checkly.Client).CreatePrivateLocation(ctx, pl) - if err != nil { - return fmt.Errorf("CreatePrivateLocation: API error: %w", err) - } - d.SetId(result.ID) - - var keys = []string{result.Keys[0].RawKey} - d.Set("keys", keys) - return resourcePrivateLocationRead(d, client) -} - -func resourceDataFromPrivateLocation(pl *checkly.PrivateLocation, d *schema.ResourceData) error { - d.Set("name", pl.Name) - d.Set("slug_name", pl.SlugName) - d.Set("icon", pl.Icon) - return nil -} - -func resourcePrivateLocationUpdate(d *schema.ResourceData, client interface{}) error { - pl, err := privateLocationFromResourceData(d) - if err != nil { - return fmt.Errorf("resourcePrivateLocationUpdate: translation error: %w", err) - } - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - _, err = client.(checkly.Client).UpdatePrivateLocation(ctx, d.Id(), pl) - if err != nil { - return fmt.Errorf("resourcePrivateLocationUpdate: API error: %w", err) - } - return resourcePrivateLocationRead(d, client) -} - -func resourcePrivateLocationRead(d *schema.ResourceData, client interface{}) error { - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - pl, err := client.(checkly.Client).GetPrivateLocation(ctx, d.Id()) - if err != nil { - if strings.Contains(err.Error(), "404") { - //if resource is deleted remotely, then mark it as - //successfully gone by unsetting it's ID - d.SetId("") - return nil - } - return fmt.Errorf("resourcePrivateLocationRead: %w", err) - } - return resourceDataFromPrivateLocation(pl, d) -} - -func resourcePrivateLocationDelete(d *schema.ResourceData, client interface{}) error { - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - err := client.(checkly.Client).DeletePrivateLocation(ctx, d.Id()) - if err != nil { - return fmt.Errorf("resourcePrivateLocationDelete: API error: %w", err) - } - return nil -} diff --git a/checkly/resource_private_locations_test.go b/checkly/resource_private_locations_test.go deleted file mode 100644 index d5e5f4e..0000000 --- a/checkly/resource_private_locations_test.go +++ /dev/null @@ -1,81 +0,0 @@ -package checkly - -import ( - "regexp" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccPrivateLocationCheckRequiredFields(t *testing.T) { - config := `resource "checkly_private_location" "test" {}` - accTestCase(t, []resource.TestStep{ - { - Config: config, - ExpectError: regexp.MustCompile(`The argument "name" is required`), - }, - { - Config: config, - ExpectError: regexp.MustCompile(`The argument "slug_name" is required`), - }, - }) -} - -func TestAccPrivateLocationSuccess(t *testing.T) { - config := `resource "checkly_private_location" "test" { - name = "New Private Location" - slug_name = "new-private-location" - icon = "bell-fill" - }` - accTestCase(t, []resource.TestStep{ - { - Config: config, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "checkly_private_location.test", - "name", - "New Private Location", - ), - resource.TestCheckResourceAttr( - "checkly_private_location.test", - "slug_name", - "new-private-location", - ), - resource.TestCheckResourceAttr( - "checkly_private_location.test", - "icon", - "bell-fill", - ), - ), - }, - }) -} - -func TestAccPrivateLocationDefaultIcon(t *testing.T) { - config := `resource "checkly_private_location" "without_icon" { - name = "New Private Location" - slug_name = "new-private-location" - }` - accTestCase(t, []resource.TestStep{ - { - Config: config, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "checkly_private_location.without_icon", - "name", - "New Private Location", - ), - resource.TestCheckResourceAttr( - "checkly_private_location.without_icon", - "slug_name", - "new-private-location", - ), - resource.TestCheckResourceAttr( - "checkly_private_location.without_icon", - "icon", - "location", - ), - ), - }, - }) -} diff --git a/checkly/resource_snippet.go b/checkly/resource_snippet.go deleted file mode 100644 index 3ea903a..0000000 --- a/checkly/resource_snippet.go +++ /dev/null @@ -1,129 +0,0 @@ -package checkly - -import ( - "context" - "fmt" - "strconv" - "strings" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - checkly "github.com/checkly/checkly-go-sdk" -) - -func resourceSnippet() *schema.Resource { - return &schema.Resource{ - Create: resourceSnippetCreate, - Read: resourceSnippetRead, - Update: resourceSnippetUpdate, - Delete: resourceSnippetDelete, - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, - }, - Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - Description: "The name of the snippet", - }, - "script": { - Type: schema.TypeString, - Required: true, - Description: "Your Node.js code that interacts with the API check lifecycle, or functions as a partial for browser checks.", - }, - }, - } -} - -func resourceSnippetCreate(d *schema.ResourceData, client interface{}) error { - snippet, err := snippetFromResourceData(d) - if err != nil { - return fmt.Errorf("resourceSnippetCreate: translation error: %w", err) - } - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - result, err := client.(checkly.Client).CreateSnippet(ctx, snippet) - if err != nil { - return fmt.Errorf("CreateSnippet: API error: %w", err) - } - d.SetId(fmt.Sprintf("%d", result.ID)) - return resourceSnippetRead(d, client) -} - -func snippetFromResourceData(d *schema.ResourceData) (checkly.Snippet, error) { - id, err := resourceIDToInt(d.Id()) - if err != nil { - return checkly.Snippet{}, err - } - return checkly.Snippet{ - ID: id, - Name: d.Get("name").(string), - Script: d.Get("script").(string), - }, nil -} - -func resourceDataFromSnippet(s *checkly.Snippet, d *schema.ResourceData) error { - d.Set("name", s.Name) - d.Set("script", s.Script) - return nil -} - -func resourceIDToInt(id string) (int64, error) { - if id == "" { - return 0, nil - } - res, err := strconv.ParseInt(id, 10, 64) - if err != nil { - return 0, err - } - return res, nil -} - -func resourceSnippetRead(d *schema.ResourceData, client interface{}) error { - ID, err := strconv.ParseInt(d.Id(), 10, 64) - if err != nil { - return fmt.Errorf("resourceSnippetRead: ID %s is not numeric: %w", d.Id(), err) - } - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - snippet, err := client.(checkly.Client).GetSnippet(ctx, ID) - if err != nil { - if strings.Contains(err.Error(), "404") { - //if resource is deleted remotely, then mark it as - //successfully gone by unsetting it's ID - d.SetId("") - return nil - } - return fmt.Errorf("resourceSnippetRead: API error: %w", err) - } - return resourceDataFromSnippet(snippet, d) -} - -func resourceSnippetUpdate(d *schema.ResourceData, client interface{}) error { - snippet, err := snippetFromResourceData(d) - if err != nil { - return fmt.Errorf("resourceSnippetUpdate: translation error: %w", err) - } - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - _, err = client.(checkly.Client).UpdateSnippet(ctx, snippet.ID, snippet) - if err != nil { - return fmt.Errorf("resourceSnippetUpdate: API error: %w", err) - } - d.SetId(fmt.Sprintf("%d", snippet.ID)) - return resourceSnippetRead(d, client) -} - -func resourceSnippetDelete(d *schema.ResourceData, client interface{}) error { - ID, err := strconv.ParseInt(d.Id(), 10, 64) - if err != nil { - return fmt.Errorf("resourceSnippetDelete: ID %s is not numeric: %w", d.Id(), err) - } - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - err = client.(checkly.Client).DeleteSnippet(ctx, ID) - if err != nil { - return fmt.Errorf("resourceSnippetDelete: API error: %w", err) - } - return nil -} diff --git a/checkly/resource_snippets_test.go b/checkly/resource_snippets_test.go deleted file mode 100644 index 08536db..0000000 --- a/checkly/resource_snippets_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package checkly - -import ( - "regexp" - "testing" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" -) - -func TestAccSnippetCheckRequiredFields(t *testing.T) { - config := `resource "checkly_snippet" "test" {}` - accTestCase(t, []resource.TestStep{ - { - Config: config, - ExpectError: regexp.MustCompile(`The argument "name" is required`), - }, - { - Config: config, - ExpectError: regexp.MustCompile(`The argument "script" is required`), - }, - }) -} - -func TestAccSnippetSuccess(t *testing.T) { - config := `resource "checkly_snippet" "test" { - name = "foo" - script = "console.log('bar')" - }` - accTestCase(t, []resource.TestStep{ - { - Config: config, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "checkly_snippet.test", - "name", - "foo", - ), - resource.TestCheckResourceAttr( - "checkly_snippet.test", - "script", - "console.log('bar')", - ), - ), - }, - }) -} diff --git a/checkly/resource_trigger_check.go b/checkly/resource_trigger_check.go deleted file mode 100644 index 18d60ee..0000000 --- a/checkly/resource_trigger_check.go +++ /dev/null @@ -1,124 +0,0 @@ -package checkly - -import ( - "context" - "fmt" - "strconv" - "strings" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - checkly "github.com/checkly/checkly-go-sdk" -) - -func resourceTriggerCheck() *schema.Resource { - return &schema.Resource{ - Create: resourceTriggerCheckCreate, - Read: resourceTriggerCheckRead, - Delete: resourceTriggerCheckDelete, - Update: resourceTriggerCheckUpdate, - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, - }, - Schema: map[string]*schema.Schema{ - "check_id": { - Type: schema.TypeString, - Required: true, - Description: "The id of the check that you want to attach the trigger to.", - }, - "token": { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "The token value created to trigger the check", - }, - "url": { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "The request URL to trigger the check run.", - }, - }, - } -} - -func triggerCheckFromResourceData(data *schema.ResourceData) (checkly.TriggerCheck, error) { - ID, err := strconv.ParseInt(data.Id(), 10, 64) - if err != nil { - if data.Id() != "" { - return checkly.TriggerCheck{}, err - } - ID = 0 - } - return checkly.TriggerCheck{ - ID: ID, - CheckId: data.Get("check_id").(string), - Token: data.Get("token").(string), - URL: data.Get("url").(string), - }, nil -} - -func resourceDataFromTriggerCheck(trigger *checkly.TriggerCheck, data *schema.ResourceData) error { - data.Set("check_id", trigger.CheckId) - data.Set("token", trigger.Token) - data.Set("url", trigger.URL) - return nil -} - -func resourceTriggerCheckCreate(data *schema.ResourceData, client interface{}) error { - trigger, err := triggerCheckFromResourceData(data) - if err != nil { - return fmt.Errorf("resourceTriggerCheckCreate: translation error: %w", err) - } - - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - result, err := client.(checkly.Client).CreateTriggerCheck(ctx, trigger.CheckId) - if err != nil { - return fmt.Errorf("CreateTriggerCheck: API error: %w", err) - } - - data.SetId(fmt.Sprintf("%d", result.ID)) - - return resourceTriggerCheckRead(data, client) -} - -func resourceTriggerCheckDelete(data *schema.ResourceData, client interface{}) error { - trigger, err := triggerCheckFromResourceData(data) - if err != nil { - return fmt.Errorf("resourceTriggerCheckDelete: translation error: %w", err) - } - - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - err = client.(checkly.Client).DeleteTriggerCheck(ctx, trigger.CheckId) - if err != nil { - return fmt.Errorf("DeleteTriggerCheck: API error: %w", err) - } - - return nil -} - -func resourceTriggerCheckRead(data *schema.ResourceData, client interface{}) error { - trigger, err := triggerCheckFromResourceData(data) - if err != nil { - return fmt.Errorf("resourceTriggerCheckRead: ID %s is not numeric: %w", data.Id(), err) - } - - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - result, err := client.(checkly.Client).GetTriggerCheck(ctx, trigger.CheckId) - defer cancel() - if err != nil { - if strings.Contains(err.Error(), "404") { - data.SetId("") - return nil - } - return fmt.Errorf("GetTriggerCheck: API error: %w", err) - } - - return resourceDataFromTriggerCheck(result, data) -} - -func resourceTriggerCheckUpdate(data *schema.ResourceData, client interface{}) error { - return resourceTriggerCheckRead(data, client) -} diff --git a/checkly/resource_trigger_group.go b/checkly/resource_trigger_group.go deleted file mode 100644 index 1b344df..0000000 --- a/checkly/resource_trigger_group.go +++ /dev/null @@ -1,123 +0,0 @@ -package checkly - -import ( - "context" - "fmt" - "strconv" - "strings" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - - checkly "github.com/checkly/checkly-go-sdk" -) - -func resourceTriggerGroup() *schema.Resource { - return &schema.Resource{ - Create: resourceTriggerGroupCreate, - Read: resourceTriggerGroupRead, - Delete: resourceTriggerGroupDelete, - Update: resourceTriggerGroupUpdate, - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, - }, - Schema: map[string]*schema.Schema{ - "group_id": { - Type: schema.TypeInt, - Required: true, - Description: "The id of the group that you want to attach the trigger to.", - }, - "token": { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "The token value created to trigger the group", - }, - "url": { - Type: schema.TypeString, - Optional: true, - Computed: true, - Description: "The request URL to trigger the group run.", - }, - }, - } -} - -func triggerGroupFromResourceData(data *schema.ResourceData) (checkly.TriggerGroup, error) { - ID, err := strconv.ParseInt(data.Id(), 10, 64) - if err != nil { - if data.Id() != "" { - return checkly.TriggerGroup{}, err - } - ID = 0 - } - - return checkly.TriggerGroup{ - ID: ID, - GroupId: int64(data.Get("group_id").(int)), - Token: data.Get("token").(string), - }, nil -} - -func resourceDataFromTriggerGroup(trigger *checkly.TriggerGroup, data *schema.ResourceData) error { - data.Set("group_id", trigger.GroupId) - data.Set("token", trigger.Token) - data.Set("url", trigger.URL) - return nil -} - -func resourceTriggerGroupCreate(data *schema.ResourceData, client interface{}) error { - tc, err := triggerGroupFromResourceData(data) - if err != nil { - return fmt.Errorf("resourceTriggerGroupCreate: translation error: %w", err) - } - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - result, err := client.(checkly.Client).CreateTriggerGroup(ctx, tc.GroupId) - - if err != nil { - return fmt.Errorf("CreateTriggerGroup: API error: %w", err) - } - - data.SetId(fmt.Sprintf("%d", result.ID)) - - return resourceTriggerGroupRead(data, client) -} - -func resourceTriggerGroupDelete(data *schema.ResourceData, client interface{}) error { - tc, err := triggerGroupFromResourceData(data) - if err != nil { - return fmt.Errorf("resourceTriggerGroupDelete: translation error: %w", err) - } - - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - defer cancel() - err = client.(checkly.Client).DeleteTriggerGroup(ctx, tc.GroupId) - if err != nil { - return fmt.Errorf("DeleteTriggerGroup: API error: %w", err) - } - - return nil -} - -func resourceTriggerGroupRead(data *schema.ResourceData, client interface{}) error { - trigger, err := triggerGroupFromResourceData(data) - if err != nil { - return fmt.Errorf("resourceTriggerGroupRead: ID %s is not numeric: %w", data.Id(), err) - } - - ctx, cancel := context.WithTimeout(context.Background(), apiCallTimeout()) - result, err := client.(checkly.Client).GetTriggerGroup(ctx, trigger.GroupId) - defer cancel() - if err != nil { - if strings.Contains(err.Error(), "404") { - data.SetId("") - return nil - } - return fmt.Errorf("GetTriggerGroup: API error: %w", err) - } - return resourceDataFromTriggerGroup(result, data) -} - -func resourceTriggerGroupUpdate(data *schema.ResourceData, client interface{}) error { - return resourceTriggerCheckRead(data, client) -} diff --git a/docs/data-sources/static_ips.md b/docs/data-sources/static_ips.md index c7c073a..5c61dc6 100644 --- a/docs/data-sources/static_ips.md +++ b/docs/data-sources/static_ips.md @@ -23,4 +23,4 @@ description: |- ### Read-Only - `addresses` (Set of String) Static IP addresses for Checkly's runner infrastructure. -- `id` (String) ID of the static IPs data source. +- `id` (String) The ID of this data source. diff --git a/docs/index.md b/docs/index.md index e487bc6..316481b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -61,14 +61,14 @@ resource "checkly_check" "example_check" { "us-west-1" ] - request { + request = { url = "https://api.example.com/" follow_redirects = true - assertion { + assertions = [{ source = "STATUS_CODE" comparison = "EQUALS" target = "200" - } + }] } } ``` @@ -76,13 +76,10 @@ resource "checkly_check" "example_check" { ## Schema -### Required - -- `api_key` (String) - ### Optional - `account_id` (String) +- `api_key` (String, Sensitive) - `api_url` (String) > For additional documentation and examples, check the Resources sections. \ No newline at end of file diff --git a/docs/resources/alert_channel.md b/docs/resources/alert_channel.md index 2672f4f..4596edf 100644 --- a/docs/resources/alert_channel.md +++ b/docs/resources/alert_channel.md @@ -3,19 +3,19 @@ page_title: "checkly_alert_channel Resource - terraform-provider-checkly" subcategory: "" description: |- - Allows you to define alerting channels for the checks and groups in your account + Allows you to define alerting channels for the checks and groups in your account. --- # checkly_alert_channel (Resource) -Allows you to define alerting channels for the checks and groups in your account +Allows you to define alerting channels for the checks and groups in your account. ## Example Usage ```terraform # An Email alert channel resource "checkly_alert_channel" "email_ac" { - email { + email = { address = "john@example.com" } send_recovery = true @@ -27,7 +27,7 @@ resource "checkly_alert_channel" "email_ac" { # A SMS alert channel resource "checkly_alert_channel" "sms_ac" { - sms { + sms = { name = "john" number = "+5491100001111" } @@ -37,7 +37,7 @@ resource "checkly_alert_channel" "sms_ac" { # A Slack alert channel resource "checkly_alert_channel" "slack_ac" { - slack { + slack = { channel = "#checkly-notifications" url = "https://hooks.slack.com/services/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" } @@ -45,7 +45,7 @@ resource "checkly_alert_channel" "slack_ac" { # An Opsgenie alert channel resource "checkly_alert_channel" "opsgenie_ac" { - opsgenie { + opsgenie = { name = "opsalerts" api_key = "fookey" region = "fooregion" @@ -55,7 +55,7 @@ resource "checkly_alert_channel" "opsgenie_ac" { # A Pagerduty alert channel resource "checkly_alert_channel" "pagerduty_ac" { - pagerduty { + pagerduty = { account = "checkly" service_key = "key1" service_name = "pdalert" @@ -64,7 +64,7 @@ resource "checkly_alert_channel" "pagerduty_ac" { # A Webhook alert channel resource "checkly_alert_channel" "webhook_ac" { - webhook { + webhook = { name = "foo" method = "get" template = "footemplate" @@ -75,7 +75,7 @@ resource "checkly_alert_channel" "webhook_ac" { # A Firehydran alert channel integration resource "checkly_alert_channel" "firehydrant_ac" { - webhook { + webhook = { name = "firehydrant" method = "post" template = < + ### Nested Schema for `call` Required: @@ -141,7 +142,7 @@ Required: - `number` (String) The mobile number to receive the alerts - + ### Nested Schema for `email` Required: @@ -149,7 +150,7 @@ Required: - `address` (String) The email address of this email alert channel. - + ### Nested Schema for `opsgenie` Required: @@ -160,7 +161,7 @@ Required: - `region` (String) - + ### Nested Schema for `pagerduty` Required: @@ -173,7 +174,7 @@ Optional: - `service_name` (String) - + ### Nested Schema for `slack` Required: @@ -182,7 +183,7 @@ Required: - `url` (String) The Slack webhook URL - + ### Nested Schema for `sms` Required: @@ -191,7 +192,7 @@ Required: - `number` (String) The mobile number to receive the alerts - + ### Nested Schema for `webhook` Required: diff --git a/docs/resources/check.md b/docs/resources/check.md index bfbddbe..b8a3ea2 100644 --- a/docs/resources/check.md +++ b/docs/resources/check.md @@ -3,12 +3,12 @@ page_title: "checkly_check Resource - terraform-provider-checkly" subcategory: "" description: |- - Checks allows you to monitor key webapp flows, backend API's and set up alerting, so you get a notification when things break or slow down. + Check groups allow you to group together a set of related checks, which can also share default settings for various attributes. --- # checkly_check (Resource) -Checks allows you to monitor key webapp flows, backend API's and set up alerting, so you get a notification when things break or slow down. +Check groups allow you to group together a set of related checks, which can also share default settings for various attributes. ## Example Usage @@ -26,15 +26,15 @@ resource "checkly_check" "example_check" { "us-west-1" ] - request { + request = { url = "https://api.example.com/" follow_redirects = true skip_ssl = false - assertion { + assertions = [{ source = "STATUS_CODE" comparison = "EQUALS" target = "200" - } + }] } } @@ -54,19 +54,19 @@ resource "checkly_check" "example_check_2" { "ap-south-1", ] - alert_settings { + alert_settings = { escalation_type = "RUN_BASED" - run_based_escalation { + run_based_escalation = { failed_run_threshold = 1 } - reminders { + reminders = { amount = 1 } } - retry_strategy { + retry_strategy = { type = "FIXED" base_backoff_seconds = 60 max_duration_seconds = 600 @@ -74,7 +74,7 @@ resource "checkly_check" "example_check_2" { same_region = false } - request { + request = { follow_redirects = true skip_ssl = false url = "http://api.example.com/" @@ -87,21 +87,21 @@ resource "checkly_check" "example_check_2" { X-Bogus = "bogus" } - assertion { + assertion = { source = "JSON_BODY" property = "code" comparison = "HAS_VALUE" target = "authentication.failed" } - assertion { + assertion = { source = "STATUS_CODE" property = "" comparison = "EQUALS" target = "401" } - basic_auth { + basic_auth = { username = "" password = "" } @@ -137,13 +137,13 @@ EOT # Connection checks with alert channels resource "checkly_alert_channel" "email_ac1" { - email { + email = { address = "info1@example.com" } } resource "checkly_alert_channel" "email_ac2" { - email { + email = { address = "info2@example.com" } } @@ -152,15 +152,16 @@ resource "checkly_check" "example_check" { name = "Example check" # ... - alert_channel_subscription { - channel_id = checkly_alert_channel.email_ac1.id - activated = true - } - - alert_channel_subscription { - channel_id = checkly_alert_channel.email_ac2.id - activated = true - } + alert_channel_subscriptions = [ + { + channel_id = checkly_alert_channel.email_ac1.id + activated = true + }, + { + channel_id = checkly_alert_channel.email_ac2.id + activated = true + } + ] } # An alternative syntax for add the script is by referencing an external file @@ -196,23 +197,23 @@ resource "checkly_check" "example_check" { ### Optional -- `alert_channel_subscription` (Block List) An array of channel IDs and whether they're activated or not. If you don't set at least one alert subscription for your check, we won't be able to alert you in case something goes wrong with it. (see [below for nested schema](#nestedblock--alert_channel_subscription)) -- `alert_settings` (Block List, Max: 1) (see [below for nested schema](#nestedblock--alert_settings)) +- `alert_channel_subscription` (Attributes List) An array of channel IDs and whether they're activated or not. If you don't set at least one alert subscription for your check, we won't be able to alert you in case something goes wrong with it. (see [below for nested schema](#nestedatt--alert_channel_subscription)) +- `alert_settings` (Attributes) (see [below for nested schema](#nestedatt--alert_settings)) - `degraded_response_time` (Number) The response time in milliseconds starting from which a check should be considered degraded. Possible values are between 0 and 30000. (Default `15000`). - `double_check` (Boolean, Deprecated) Setting this to `true` will trigger a retry when a check fails from the failing region and another, randomly selected region before marking the check as failed. -- `environment_variable` (Block List) Key/value pairs for setting environment variables during check execution, add locked = true to keep value hidden, add secret = true to create a secret variable. These are only relevant for browser checks. Use global environment variables whenever possible. (see [below for nested schema](#nestedblock--environment_variable)) +- `environment_variable` (Attributes List) Introduce additional environment variables to the check execution environment. Only relevant for browser checks. Prefer global environment variables when possible. (see [below for nested schema](#nestedatt--environment_variable)) - `environment_variables` (Map of String, Deprecated) Key/value pairs for setting environment variables during check execution. These are only relevant for browser checks. Use global environment variables whenever possible. -- `frequency_offset` (Number) This property only valid for API high frequency checks. To create a hight frequency check, the property `frequency` must be `0` and `frequency_offset` could be `10`, `20` or `30`. +- `frequency_offset` (Number) This property is only valid for high frequency API checks. To create a high frequency check, the property `frequency` must be `0` and `frequency_offset` could be `10`, `20` or `30`. - `group_id` (Number) The id of the check group this check is part of. - `group_order` (Number) The position of this check in a check group. It determines in what order checks are run when a group is triggered from the API or from CI/CD. - `local_setup_script` (String) A valid piece of Node.js code to run in the setup phase. - `local_teardown_script` (String) A valid piece of Node.js code to run in the teardown phase. -- `locations` (Set of String) An array of one or more data center locations where to run the this check. (Default ["us-east-1"]) +- `locations` (Set of String) An array of one or more data center locations where to run the checks. - `max_response_time` (Number) The response time in milliseconds starting from which a check should be considered failing. Possible values are between 0 and 30000. (Default `30000`). - `muted` (Boolean) Determines if any notifications will be sent out when a check fails/degrades/recovers. - `private_locations` (Set of String) An array of one or more private locations slugs. -- `request` (Block Set, Max: 1) An API check might have one request config. (see [below for nested schema](#nestedblock--request)) -- `retry_strategy` (Block Set, Max: 1) A strategy for retrying failed check runs. (see [below for nested schema](#nestedblock--retry_strategy)) +- `request` (Attributes) (see [below for nested schema](#nestedatt--request)) +- `retry_strategy` (Attributes) A strategy for retrying failed check runs. (see [below for nested schema](#nestedatt--retry_strategy)) - `run_parallel` (Boolean) Determines if the check should run in all selected locations in parallel or round-robin. - `runtime_id` (String) The id of the runtime to use for this check. - `script` (String) A valid piece of Node.js JavaScript code describing a browser interaction with the Puppeteer/Playwright framework or a reference to an external JavaScript file. @@ -220,7 +221,7 @@ resource "checkly_check" "example_check" { - `should_fail` (Boolean) Allows to invert the behaviour of when a check is considered to fail. Allows for validating error status like 404. - `ssl_check` (Boolean, Deprecated) Determines if the SSL certificate should be validated for expiry. - `ssl_check_domain` (String) A valid fully qualified domain name (FQDN) to check its SSL certificate. -- `tags` (Set of String) A list of tags for organizing and filtering checks. +- `tags` (Set of String) Tags for organizing and filtering checks. - `teardown_snippet_id` (Number) An ID reference to a snippet to use in the teardown phase of an API check. - `use_global_alert_settings` (Boolean) When true, the account level alert settings will be used, not the alert setting defined on this check. @@ -228,7 +229,7 @@ resource "checkly_check" "example_check" { - `id` (String) The ID of this resource. - + ### Nested Schema for `alert_channel_subscription` Required: @@ -237,28 +238,28 @@ Required: - `channel_id` (Number) - + ### Nested Schema for `alert_settings` Optional: - `escalation_type` (String) Determines what type of escalation to use. Possible values are `RUN_BASED` or `TIME_BASED`. -- `parallel_run_failure_threshold` (Block List) (see [below for nested schema](#nestedblock--alert_settings--parallel_run_failure_threshold)) -- `reminders` (Block List) (see [below for nested schema](#nestedblock--alert_settings--reminders)) -- `run_based_escalation` (Block List) (see [below for nested schema](#nestedblock--alert_settings--run_based_escalation)) -- `ssl_certificates` (Block Set, Deprecated) (see [below for nested schema](#nestedblock--alert_settings--ssl_certificates)) -- `time_based_escalation` (Block List) (see [below for nested schema](#nestedblock--alert_settings--time_based_escalation)) +- `parallel_run_failure_threshold` (Attributes) (see [below for nested schema](#nestedatt--alert_settings--parallel_run_failure_threshold)) +- `reminders` (Attributes) (see [below for nested schema](#nestedatt--alert_settings--reminders)) +- `run_based_escalation` (Attributes) (see [below for nested schema](#nestedatt--alert_settings--run_based_escalation)) +- `ssl_certificates` (Attributes, Deprecated) At what interval the reminders should be sent. (see [below for nested schema](#nestedatt--alert_settings--ssl_certificates)) +- `time_based_escalation` (Attributes) (see [below for nested schema](#nestedatt--alert_settings--time_based_escalation)) - + ### Nested Schema for `alert_settings.parallel_run_failure_threshold` Optional: - `enabled` (Boolean) Applicable only for checks scheduled in parallel in multiple locations. -- `percentage` (Number) Possible values are `10`, `20`, `30`, `40`, `50`, `60`, `70`, `80`, `100`, and `100`. (Default `10`). +- `percentage` (Number) Possible values are `10`, `20`, `30`, `40`, `50`, `60`, `70`, `80`, `90`, and `100`. (Default `10`). - + ### Nested Schema for `alert_settings.reminders` Optional: @@ -267,7 +268,7 @@ Optional: - `interval` (Number) Possible values are `5`, `10`, `15`, and `30`. (Default `5`). - + ### Nested Schema for `alert_settings.run_based_escalation` Optional: @@ -275,7 +276,7 @@ Optional: - `failed_run_threshold` (Number) After how many failed consecutive check runs an alert notification should be sent. Possible values are between 1 and 5. (Default `1`). - + ### Nested Schema for `alert_settings.ssl_certificates` Optional: @@ -284,7 +285,7 @@ Optional: - `enabled` (Boolean) Determines if alert notifications should be sent for expiring SSL certificates. Possible values `true`, and `false`. (Default `false`). - + ### Nested Schema for `alert_settings.time_based_escalation` Optional: @@ -293,21 +294,21 @@ Optional: - + ### Nested Schema for `environment_variable` Required: -- `key` (String) -- `value` (String) +- `key` (String) The name of the environment variable. +- `value` (String, Sensitive) The value of the environment variable. By default the value is plain text and can be seen by any team member. It will also be present in check results and logs. Optional: -- `locked` (Boolean) -- `secret` (Boolean) +- `locked` (Boolean) Locked environment variables are encrypted at rest and in flight on the Checkly backend and are only decrypted when needed. Their value is hidden by default, but can be accessed by team members with the appropriate permissions. +- `secret` (Boolean) Secret environment variables are always encrypted and their value is never shown to any user. However, keep in mind that your Terraform state will still contain the value. - + ### Nested Schema for `request` Required: @@ -316,8 +317,8 @@ Required: Optional: -- `assertion` (Block Set) A request can have multiple assertions. (see [below for nested schema](#nestedblock--request--assertion)) -- `basic_auth` (Block Set, Max: 1) Set up HTTP basic authentication (username & password). (see [below for nested schema](#nestedblock--request--basic_auth)) +- `assertion` (Attributes List) (see [below for nested schema](#nestedatt--request--assertion)) +- `basic_auth` (Attributes) Credentials for Basic HTTP authentication. (see [below for nested schema](#nestedatt--request--basic_auth)) - `body` (String) The body of the request. - `body_type` (String) The `Content-Type` header of the request. Possible values `NONE`, `JSON`, `FORM`, `RAW`, and `GRAPHQL`. - `follow_redirects` (Boolean) @@ -327,31 +328,31 @@ Optional: - `query_parameters` (Map of String) - `skip_ssl` (Boolean) - + ### Nested Schema for `request.assertion` Required: - `comparison` (String) The type of comparison to be executed between expected and actual value of the assertion. Possible values `EQUALS`, `NOT_EQUALS`, `HAS_KEY`, `NOT_HAS_KEY`, `HAS_VALUE`, `NOT_HAS_VALUE`, `IS_EMPTY`, `NOT_EMPTY`, `GREATER_THAN`, `LESS_THAN`, `CONTAINS`, `NOT_CONTAINS`, `IS_NULL`, and `NOT_NULL`. - `source` (String) The source of the asserted value. Possible values `STATUS_CODE`, `JSON_BODY`, `HEADERS`, `TEXT_BODY`, and `RESPONSE_TIME`. +- `target` (String) Optional: - `property` (String) -- `target` (String) - + ### Nested Schema for `request.basic_auth` Required: -- `password` (String) +- `password` (String, Sensitive) - `username` (String) - + ### Nested Schema for `retry_strategy` Required: diff --git a/docs/resources/check_group.md b/docs/resources/check_group.md index 9fc618b..5a1fa31 100644 --- a/docs/resources/check_group.md +++ b/docs/resources/check_group.md @@ -3,12 +3,12 @@ page_title: "checkly_check_group Resource - terraform-provider-checkly" subcategory: "" description: |- - Check groups allow you to group together a set of related checks, which can also share default settings for various attributes. + Check groups allow you to group together a set of related checks, which can also share default settings for various attributes. --- # checkly_check_group (Resource) -Check groups allow you to group together a set of related checks, which can also share default settings for various attributes. +Check groups allow you to group together a set of related checks, which can also share default settings for various attributes. ## Example Usage @@ -25,7 +25,7 @@ resource "checkly_check_group" "test_group1" { "eu-west-1", ] concurrency = 3 - api_check_defaults { + api_check_defaults = { url = "http://example.com/" headers = { X-Test = "foo" @@ -35,48 +35,49 @@ resource "checkly_check_group" "test_group1" { query = "foo" } - assertion { + assertion = { source = "STATUS_CODE" property = "" comparison = "EQUALS" target = "200" } - assertion { + assertion = { source = "TEXT_BODY" property = "" comparison = "CONTAINS" target = "welcome" } - basic_auth { + basic_auth = { username = "user" password = "pass" } } - environment_variable { - key = "TEST_ENV_VAR" - value = "Hello world" - locked = false - } - - environment_variable { - key = "ADDITIONAL_ENV_VAR" - value = "test value" - locked = true - } + environment_variables = [ + { + key = "TEST_ENV_VAR" + value = "Hello world" + locked = false + }, + { + key = "ADDITIONAL_ENV_VAR" + value = "test value" + locked = true + } + ] use_global_alert_settings = false - alert_settings { + alert_settings = { escalation_type = "RUN_BASED" - run_based_escalation { + run_based_escalation = { failed_run_threshold = 1 } - reminders { + reminders = { amount = 2 interval = 5 } @@ -96,7 +97,7 @@ resource "checkly_check" "test_check1" { "us-west-1" ] - request { + request = { url = "https://api.example.com/" } group_id = checkly_check_group.test_group1.id @@ -106,13 +107,13 @@ resource "checkly_check" "test_check1" { # Using with alert channels resource "checkly_alert_channel" "email_ac1" { - email { + email = { address = "info@example.com" } } resource "checkly_alert_channel" "email_ac2" { - email { + email = { address = "info2@example.com" } } @@ -122,15 +123,16 @@ resource "checkly_alert_channel" "email_ac2" { resource "checkly_check_group" "test_group1" { name = "My test group 1" - alert_channel_subscription { - channel_id = checkly_alert_channel.email_ac1.id - activated = true - } - - alert_channel_subscription { - channel_id = checkly_alert_channel.email_ac2.id - activated = true - } + alert_channel_subscriptions = [ + { + channel_id = checkly_alert_channel.email_ac1.id + activated = true + }, + { + channel_id = checkly_alert_channel.email_ac2.id + activated = true + } + ] } ``` @@ -145,18 +147,18 @@ resource "checkly_check_group" "test_group1" { ### Optional -- `alert_channel_subscription` (Block List) (see [below for nested schema](#nestedblock--alert_channel_subscription)) -- `alert_settings` (Block List, Max: 1) (see [below for nested schema](#nestedblock--alert_settings)) -- `api_check_defaults` (Block Set, Max: 1) (see [below for nested schema](#nestedblock--api_check_defaults)) +- `alert_channel_subscription` (Attributes List) An array of channel IDs and whether they're activated or not. If you don't set at least one alert subscription for your check, we won't be able to alert you in case something goes wrong with it. (see [below for nested schema](#nestedatt--alert_channel_subscription)) +- `alert_settings` (Attributes) (see [below for nested schema](#nestedatt--alert_settings)) +- `api_check_defaults` (Attributes) (see [below for nested schema](#nestedatt--api_check_defaults)) - `double_check` (Boolean, Deprecated) Setting this to `true` will trigger a retry when a check fails from the failing region and another, randomly selected region before marking the check as failed. -- `environment_variable` (Block List) Key/value pairs for setting environment variables during check execution, add locked = true to keep value hidden, add secret = true to create a secret variable. These are only relevant for browser checks. Use global environment variables whenever possible. (see [below for nested schema](#nestedblock--environment_variable)) +- `environment_variable` (Attributes List) Introduce additional environment variables to the check execution environment. Only relevant for browser checks. Prefer global environment variables when possible. (see [below for nested schema](#nestedatt--environment_variable)) - `environment_variables` (Map of String, Deprecated) Key/value pairs for setting environment variables during check execution. These are only relevant for browser checks. Use global environment variables whenever possible. - `local_setup_script` (String) A valid piece of Node.js code to run in the setup phase of an API check in this group. - `local_teardown_script` (String) A valid piece of Node.js code to run in the teardown phase of an API check in this group. - `locations` (Set of String) An array of one or more data center locations where to run the checks. - `muted` (Boolean) Determines if any notifications will be sent out when a check in this group fails and/or recovers. - `private_locations` (Set of String) An array of one or more private locations slugs. -- `retry_strategy` (Block Set, Max: 1) A strategy for retrying failed check runs. (see [below for nested schema](#nestedblock--retry_strategy)) +- `retry_strategy` (Attributes) A strategy for retrying failed check runs. (see [below for nested schema](#nestedatt--retry_strategy)) - `run_parallel` (Boolean) Determines if the checks in the group should run in all selected locations in parallel or round-robin. - `runtime_id` (String) The id of the runtime to use for this group. - `setup_snippet_id` (Number) An ID reference to a snippet to use in the setup phase of an API check. @@ -168,7 +170,7 @@ resource "checkly_check_group" "test_group1" { - `id` (String) The ID of this resource. - + ### Nested Schema for `alert_channel_subscription` Required: @@ -177,28 +179,28 @@ Required: - `channel_id` (Number) - + ### Nested Schema for `alert_settings` Optional: - `escalation_type` (String) Determines what type of escalation to use. Possible values are `RUN_BASED` or `TIME_BASED`. -- `parallel_run_failure_threshold` (Block List) (see [below for nested schema](#nestedblock--alert_settings--parallel_run_failure_threshold)) -- `reminders` (Block List) (see [below for nested schema](#nestedblock--alert_settings--reminders)) -- `run_based_escalation` (Block List) (see [below for nested schema](#nestedblock--alert_settings--run_based_escalation)) -- `ssl_certificates` (Block Set, Deprecated) (see [below for nested schema](#nestedblock--alert_settings--ssl_certificates)) -- `time_based_escalation` (Block List) (see [below for nested schema](#nestedblock--alert_settings--time_based_escalation)) +- `parallel_run_failure_threshold` (Attributes) (see [below for nested schema](#nestedatt--alert_settings--parallel_run_failure_threshold)) +- `reminders` (Attributes) (see [below for nested schema](#nestedatt--alert_settings--reminders)) +- `run_based_escalation` (Attributes) (see [below for nested schema](#nestedatt--alert_settings--run_based_escalation)) +- `ssl_certificates` (Attributes, Deprecated) At what interval the reminders should be sent. (see [below for nested schema](#nestedatt--alert_settings--ssl_certificates)) +- `time_based_escalation` (Attributes) (see [below for nested schema](#nestedatt--alert_settings--time_based_escalation)) - + ### Nested Schema for `alert_settings.parallel_run_failure_threshold` Optional: - `enabled` (Boolean) Applicable only for checks scheduled in parallel in multiple locations. -- `percentage` (Number) Possible values are `10`, `20`, `30`, `40`, `50`, `60`, `70`, `80`, `100`, and `100`. (Default `10`). +- `percentage` (Number) Possible values are `10`, `20`, `30`, `40`, `50`, `60`, `70`, `80`, `90`, and `100`. (Default `10`). - + ### Nested Schema for `alert_settings.reminders` Optional: @@ -207,7 +209,7 @@ Optional: - `interval` (Number) Possible values are `5`, `10`, `15`, and `30`. (Default `5`). - + ### Nested Schema for `alert_settings.run_based_escalation` Optional: @@ -215,16 +217,16 @@ Optional: - `failed_run_threshold` (Number) After how many failed consecutive check runs an alert notification should be sent. Possible values are between 1 and 5. (Default `1`). - + ### Nested Schema for `alert_settings.ssl_certificates` Optional: -- `alert_threshold` (Number) At what moment in time to start alerting on SSL certificates. Possible values `3`, `7`, `14`, `30`. (Default `3`). -- `enabled` (Boolean) Determines if alert notifications should be sent for expiring SSL certificates. +- `alert_threshold` (Number) How long before SSL certificate expiry to send alerts. Possible values `3`, `7`, `14`, `30`. (Default `3`). +- `enabled` (Boolean) Determines if alert notifications should be sent for expiring SSL certificates. Possible values `true`, and `false`. (Default `false`). - + ### Nested Schema for `alert_settings.time_based_escalation` Optional: @@ -233,7 +235,7 @@ Optional: - + ### Nested Schema for `api_check_defaults` Required: @@ -242,12 +244,12 @@ Required: Optional: -- `assertion` (Block Set) (see [below for nested schema](#nestedblock--api_check_defaults--assertion)) -- `basic_auth` (Block Set, Max: 1) (see [below for nested schema](#nestedblock--api_check_defaults--basic_auth)) +- `assertion` (Attributes List) (see [below for nested schema](#nestedatt--api_check_defaults--assertion)) +- `basic_auth` (Attributes) Credentials for Basic HTTP authentication. (see [below for nested schema](#nestedatt--api_check_defaults--basic_auth)) - `headers` (Map of String) - `query_parameters` (Map of String) - + ### Nested Schema for `api_check_defaults.assertion` Required: @@ -261,31 +263,31 @@ Optional: - `property` (String) - + ### Nested Schema for `api_check_defaults.basic_auth` Required: -- `password` (String) +- `password` (String, Sensitive) - `username` (String) - + ### Nested Schema for `environment_variable` Required: -- `key` (String) -- `value` (String) +- `key` (String) The name of the environment variable. +- `value` (String, Sensitive) The value of the environment variable. By default the value is plain text and can be seen by any team member. It will also be present in check results and logs. Optional: -- `locked` (Boolean) -- `secret` (Boolean) +- `locked` (Boolean) Locked environment variables are encrypted at rest and in flight on the Checkly backend and are only decrypted when needed. Their value is hidden by default, but can be accessed by team members with the appropriate permissions. +- `secret` (Boolean) Secret environment variables are always encrypted and their value is never shown to any user. However, keep in mind that your Terraform state will still contain the value. - + ### Nested Schema for `retry_strategy` Required: diff --git a/docs/resources/environment_variable.md b/docs/resources/environment_variable.md index 4308265..8cba751 100644 --- a/docs/resources/environment_variable.md +++ b/docs/resources/environment_variable.md @@ -32,7 +32,7 @@ resource "checkly_environment_variable" "variable_2" { ### Required - `key` (String) -- `value` (String) +- `value` (String, Sensitive) ### Optional diff --git a/docs/resources/heartbeat.md b/docs/resources/heartbeat.md index 279c19c..b611007 100644 --- a/docs/resources/heartbeat.md +++ b/docs/resources/heartbeat.md @@ -16,7 +16,7 @@ Heartbeats allows you to monitor your cron jobs and set up alerting, so you get resource "checkly_heartbeat" "example-heartbeat" { name = "Example heartbeat" activated = true - heartbeat { + heartbeat = { period = 7 period_unit = "days" grace = 1 @@ -32,13 +32,13 @@ resource "checkly_heartbeat" "example-heartbeat" { ### Required - `activated` (Boolean) Determines if the check is running or not. Possible values `true`, and `false`. -- `heartbeat` (Block Set, Min: 1, Max: 1) (see [below for nested schema](#nestedblock--heartbeat)) +- `heartbeat` (Attributes) (see [below for nested schema](#nestedatt--heartbeat)) - `name` (String) The name of the check. ### Optional -- `alert_channel_subscription` (Block List) (see [below for nested schema](#nestedblock--alert_channel_subscription)) -- `alert_settings` (Block List, Max: 1) (see [below for nested schema](#nestedblock--alert_settings)) +- `alert_channel_subscription` (Attributes List) An array of channel IDs and whether they're activated or not. If you don't set at least one alert subscription for your check, we won't be able to alert you in case something goes wrong with it. (see [below for nested schema](#nestedatt--alert_channel_subscription)) +- `alert_settings` (Attributes) (see [below for nested schema](#nestedatt--alert_settings)) - `muted` (Boolean) Determines if any notifications will be sent out when a check fails/degrades/recovers. - `tags` (Set of String) A list of tags for organizing and filtering checks. - `use_global_alert_settings` (Boolean) When true, the account level alert settings will be used, not the alert setting defined on this check. @@ -47,7 +47,7 @@ resource "checkly_heartbeat" "example-heartbeat" { - `id` (String) The ID of this resource. - + ### Nested Schema for `heartbeat` Required: @@ -57,12 +57,12 @@ Required: - `period` (Number) How often you expect a ping to the ping URL. - `period_unit` (String) Possible values `seconds`, `minutes`, `hours` and `days`. -Optional: +Read-Only: - `ping_token` (String) Custom token to generate your ping URL. Checkly will expect a ping to `https://ping.checklyhq.com/[PING_TOKEN]`. - + ### Nested Schema for `alert_channel_subscription` Required: @@ -71,28 +71,28 @@ Required: - `channel_id` (Number) - + ### Nested Schema for `alert_settings` Optional: - `escalation_type` (String) Determines what type of escalation to use. Possible values are `RUN_BASED` or `TIME_BASED`. -- `parallel_run_failure_threshold` (Block List) (see [below for nested schema](#nestedblock--alert_settings--parallel_run_failure_threshold)) -- `reminders` (Block List) (see [below for nested schema](#nestedblock--alert_settings--reminders)) -- `run_based_escalation` (Block List) (see [below for nested schema](#nestedblock--alert_settings--run_based_escalation)) -- `ssl_certificates` (Block Set, Deprecated) (see [below for nested schema](#nestedblock--alert_settings--ssl_certificates)) -- `time_based_escalation` (Block List) (see [below for nested schema](#nestedblock--alert_settings--time_based_escalation)) +- `parallel_run_failure_threshold` (Attributes) (see [below for nested schema](#nestedatt--alert_settings--parallel_run_failure_threshold)) +- `reminders` (Attributes) (see [below for nested schema](#nestedatt--alert_settings--reminders)) +- `run_based_escalation` (Attributes) (see [below for nested schema](#nestedatt--alert_settings--run_based_escalation)) +- `ssl_certificates` (Attributes, Deprecated) At what interval the reminders should be sent. (see [below for nested schema](#nestedatt--alert_settings--ssl_certificates)) +- `time_based_escalation` (Attributes) (see [below for nested schema](#nestedatt--alert_settings--time_based_escalation)) - + ### Nested Schema for `alert_settings.parallel_run_failure_threshold` Optional: - `enabled` (Boolean) Applicable only for checks scheduled in parallel in multiple locations. -- `percentage` (Number) Possible values are `10`, `20`, `30`, `40`, `50`, `60`, `70`, `80`, `100`, and `100`. (Default `10`). +- `percentage` (Number) Possible values are `10`, `20`, `30`, `40`, `50`, `60`, `70`, `80`, `90`, and `100`. (Default `10`). - + ### Nested Schema for `alert_settings.reminders` Optional: @@ -101,7 +101,7 @@ Optional: - `interval` (Number) Possible values are `5`, `10`, `15`, and `30`. (Default `5`). - + ### Nested Schema for `alert_settings.run_based_escalation` Optional: @@ -109,7 +109,7 @@ Optional: - `failed_run_threshold` (Number) After how many failed consecutive check runs an alert notification should be sent. Possible values are between 1 and 5. (Default `1`). - + ### Nested Schema for `alert_settings.ssl_certificates` Optional: @@ -118,7 +118,7 @@ Optional: - `enabled` (Boolean) Determines if alert notifications should be sent for expiring SSL certificates. Possible values `true`, and `false`. (Default `false`). - + ### Nested Schema for `alert_settings.time_based_escalation` Optional: diff --git a/docs/resources/snippet.md b/docs/resources/snippet.md index d9dbced..2dd64ba 100644 --- a/docs/resources/snippet.md +++ b/docs/resources/snippet.md @@ -43,7 +43,7 @@ EOT ### Required -- `name` (String) The name of the snippet +- `name` (String) The name of the snippet. - `script` (String) Your Node.js code that interacts with the API check lifecycle, or functions as a partial for browser checks. ### Read-Only diff --git a/docs/resources/trigger_check.md b/docs/resources/trigger_check.md index 06134eb..0fbf5eb 100644 --- a/docs/resources/trigger_check.md +++ b/docs/resources/trigger_check.md @@ -27,11 +27,11 @@ output "test_trigger_check_url" { ### Required -- `check_id` (String) The id of the check that you want to attach the trigger to. +- `check_id` (String) The ID of the check that you want to attach the trigger to. ### Optional -- `token` (String) The token value created to trigger the check +- `token` (String) The token value created to trigger the check. - `url` (String) The request URL to trigger the check run. ### Read-Only diff --git a/docs/resources/trigger_group.md b/docs/resources/trigger_group.md index 51e0dd0..b51da1a 100644 --- a/docs/resources/trigger_group.md +++ b/docs/resources/trigger_group.md @@ -27,11 +27,11 @@ output "test_trigger_group_url" { ### Required -- `group_id` (Number) The id of the group that you want to attach the trigger to. +- `group_id` (Number) The ID of the group that you want to attach the trigger to. ### Optional -- `token` (String) The token value created to trigger the group +- `token` (String) The token value created to trigger the group. - `url` (String) The request URL to trigger the group run. ### Read-Only diff --git a/examples/provider/provider.tf b/examples/provider/provider.tf index 16499e0..05482bc 100644 --- a/examples/provider/provider.tf +++ b/examples/provider/provider.tf @@ -31,13 +31,13 @@ resource "checkly_check" "example_check" { "us-west-1" ] - request { + request = { url = "https://api.example.com/" follow_redirects = true - assertion { + assertions = [{ source = "STATUS_CODE" comparison = "EQUALS" target = "200" - } + }] } -} \ No newline at end of file +} diff --git a/examples/resources/checkly_alert_channel/resource.tf b/examples/resources/checkly_alert_channel/resource.tf index b581b60..05e63d5 100644 --- a/examples/resources/checkly_alert_channel/resource.tf +++ b/examples/resources/checkly_alert_channel/resource.tf @@ -1,6 +1,6 @@ # An Email alert channel resource "checkly_alert_channel" "email_ac" { - email { + email = { address = "john@example.com" } send_recovery = true @@ -12,7 +12,7 @@ resource "checkly_alert_channel" "email_ac" { # A SMS alert channel resource "checkly_alert_channel" "sms_ac" { - sms { + sms = { name = "john" number = "+5491100001111" } @@ -22,7 +22,7 @@ resource "checkly_alert_channel" "sms_ac" { # A Slack alert channel resource "checkly_alert_channel" "slack_ac" { - slack { + slack = { channel = "#checkly-notifications" url = "https://hooks.slack.com/services/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" } @@ -30,7 +30,7 @@ resource "checkly_alert_channel" "slack_ac" { # An Opsgenie alert channel resource "checkly_alert_channel" "opsgenie_ac" { - opsgenie { + opsgenie = { name = "opsalerts" api_key = "fookey" region = "fooregion" @@ -40,7 +40,7 @@ resource "checkly_alert_channel" "opsgenie_ac" { # A Pagerduty alert channel resource "checkly_alert_channel" "pagerduty_ac" { - pagerduty { + pagerduty = { account = "checkly" service_key = "key1" service_name = "pdalert" @@ -49,7 +49,7 @@ resource "checkly_alert_channel" "pagerduty_ac" { # A Webhook alert channel resource "checkly_alert_channel" "webhook_ac" { - webhook { + webhook = { name = "foo" method = "get" template = "footemplate" @@ -60,7 +60,7 @@ resource "checkly_alert_channel" "webhook_ac" { # A Firehydran alert channel integration resource "checkly_alert_channel" "firehydrant_ac" { - webhook { + webhook = { name = "firehydrant" method = "post" template = <