Getting started with Terraform and StatusPal status pages

Learn how to provision your StatusPal status page, including monitoring and incident automation, with Terraform in this step-by-step guide.

Introduction

Terraform, created by HashiCorp, is a popular infrastructure-as-code software tool used to provision various types of infrastructure and services, including StatusPal status pages, monitoring checks, and incident automation.

This step-by-step guide teaches you how to set up StatusPal status pages with Terraform from the ground up, including the following resources:

  1. StatuPal status page

  2. Status page services

  3. Enable monitoring checks for your services

  4. Configure incident automation from external monitoring services

Before you begin

To use this guide, you should have some basic knowledge of both StatusPal and Terraform. If you don't have a StatusPal account, you can register here. Also, you will need to install the Terraform CLI.

1. Bootstrap Terraform and the StatusPal provider

Start by initializing a working directory and creating a Terraform configuration file:

mkdir terraform-statuspal && cd terraform-statuspal
touch main.tf

Next, instruct Terraform to install and use the StatusPal provider, by setting the terraform and required_providers blocks in main.tf:

terraform {
  # Require Terraform version >= 1.1.0
  required_version = ">= 1.1.0"

  # Require the latest version of the StatusPal provider
  # You can find it here: https://registry.terraform.io/providers/statuspal/statuspal/latest
  required_providers {
    statuspal = {
      source  = "statuspal/statuspal"
      version = "0.2.7"
    }
  }
}

In this code block, you're setting the required version of Terraform to 1.9.0 and setting the StatusPal provider to the latest version. Using the right version constraints for your setup will provide better stability with your Terraform runs.

Now that you've set your Terraform and StatusPal provider versions, you need to configure the StatusPal provider.

2. Configure the StatusPal provider

With terraform all set, configure the StatusPal provider with the following items:

  1. Your StatusPal API key, it can be a user API key or an organization API key.

  2. Your StatusPal region. It can be US or EU.

In main.tf, set those values on the provider:

provider "statuspal" {
  api_key = "uk_aERPQU1kUzUrRmplaXJRMlc2TDEwZz09" # Your Statuspal user or organization API key
  region  = "US"                                  # US or EU
}

By setting these values on the StatusPal provider, you're configuring that provider to make changes on behalf of your account through StatusPal APIs.

You can also configure the StatusPal provider using environment variables. This is a useful way to set default values for your provider configuration.

For more information about configuring the StatusPal provider, please feel free to check out our official provider documentation.

With your StatusPal provider configured, initialize Terraform:

terraform init

When Terraform finishes installing and registering the StatusPal provider, you'll receive a success message and some actionable next steps, such as running terraform plan. Before you can run terraform plan, however, you need to create your resources.

3. Configure a status page with services

With the StatusPal provider configured and initialized, you can define a status page.

Using the statuspal_status_page resource you can create an example status page:

resource "statuspal_status_page" "example" {
  organization_id = "1" # Your StatusPal organization ID. Find it in your organization's settings (https://docs.statuspal.io/faq#how-to-access-my-statuspal-organizations-settings), at the end of the URL (e.g. /admin/orgs/1)
  status_page = {
    name      = "Example Terraform Status Page"
    url       = "example.com"
    time_zone = "America/New_York"
  }
}

Now you should be able to test your configuration with a dry run:

terraform plan

You should see output that displays Terraform's execution plan. The plan contains the actions Terraform performs when your run terraform apply:

# Example output
------------------------------------------------------------------------

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # statuspal_status_page.example will be created
  + resource "statuspal_status_page" "example" {
      + id              = (known after apply)
      + organization_id = "4612"
      + status_page     = {
          + about                             = (known after apply)
          + bg_image                          = (known after apply)
          + calendar_enabled                  = (known after apply)
          + captcha_enabled                   = true
          + current_incidents_position        = "below_services"
          + custom_css                        = (known after apply)
          + custom_domain_enabled             = (known after apply)
          + custom_footer                     = (known after apply)
          + custom_header                     = (known after apply)
          + custom_incident_types_enabled     = (known after apply)
          + custom_js                         = (known after apply)
          + date_format                       = (known after apply)
          + date_format_enforce_everywhere    = (known after apply)
          + discord_notifications_enabled     = (known after apply)
          + display_about                     = (known after apply)
          + display_calendar                  = true
          + display_uptime_graph              = true
          + domain                            = (known after apply)
          + email_confirmation_template       = (known after apply)
          + email_layout_template             = (known after apply)
          + email_notification_template       = (known after apply)
          + email_templates_enabled           = (known after apply)
          + enable_auto_translations          = (known after apply)
          + feed_enabled                      = true
          + google_calendar_enabled           = (known after apply)
          + google_chat_notifications_enabled = (known after apply)
          + head_code                         = (known after apply)
          + header_bg_color1                  = "009688"
          + header_bg_color2                  = "0c91c3"
          + header_fg_color                   = "ffffff"
          + header_logo_text                  = (known after apply)
          + hide_watermark                    = (known after apply)
          + history_limit_days                = 90
          + incident_header_color             = "009688"
          + incident_link_color               = (known after apply)
          + info_notices_enabled              = true
          + inserted_at                       = (known after apply)
          + link_color                        = "0c91c3"
          + locked_when_maintenance           = (known after apply)
          + maintenance_notification_hours    = 6
          + major_notification_hours          = 3
          + mattermost_notifications_enabled  = (known after apply)
          + member_restricted                 = (known after apply)
          + minor_notification_hours          = 6
          + name                              = "Example Terraform Status Page"
          + noindex                           = (known after apply)
          + notification_email                = (known after apply)
          + notify_by_default                 = (known after apply)
          + public_company_name               = (known after apply)
          + reply_to_email                    = (known after apply)
          + restricted_ips                    = (known after apply)
          + scheduled_maintenance_days        = 7
          + slack_subscriptions_enabled       = (known after apply)
          + sms_notifications_enabled         = (known after apply)
          + status_maintenance_color          = "5378c1"
          + status_major_color                = "e75a53"
          + status_minor_color                = "FFA500"
          + status_ok_color                   = "48CBA5"
          + subdomain                         = (known after apply)
          + subscribers_enabled               = true
          + support_email                     = (known after apply)
          + teams_notifications_enabled       = (known after apply)
          + theme_configs                     = (known after apply)
          + theme_selected                    = "default"
          + time_format                       = (known after apply)
          + time_zone                         = "America/New_York"
          + translations                      = (known after apply)
          + tweet_by_default                  = (known after apply)
          + tweeting_enabled                  = true
          + twitter_public_screen_name        = (known after apply)
          + updated_at                        = (known after apply)
          + uptime_graph_days                 = 90
          + url                               = "example.com"
        }
    }

Plan: 1 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

In this case, the plan shows you that Terraform will create a new status page when you run terraform apply. After verifying the details, execute the plan to provision the status page resource in your StatusPal account:

terraform apply

Every time you apply changes, Terraform asks you to confirm the actions you've told it to run. Type "yes".

While it's running, Terraform sends logs to your console:

statuspal_status_page.example: Creating...
statuspal_status_page.example: Creation complete after 1s [id=placeholder]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Log in to StatusPal and navigate to /admin/orgs/:organization_id to confirm that Terraform created your new status page in your organization.


At this point you can add services to your status page:

# Manage example service of the previously defined example status page's subdomain.
resource "statuspal_service" "example" {
  status_page_subdomain = statuspal_status_page.example.status_page.subdomain
  service = {
    name = "Example Terraform Service"
  }
}

# Manage example child service of the previously defined example service.
resource "statuspal_service" "child" {
  status_page_subdomain = statuspal_status_page.example.status_page.subdomain
  service = {
    name      = "Example Terraform Child Service"
    parent_id = statuspal_service.example.service.id
  }
}

Run terraform plan again to see what will happen if you apply the plan.

terraform plan

You should see the following output:

# Example output
------------------------------------------------------------------------

statuspal_status_page.example: Refreshing state... [id=placeholder]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # statuspal_service.child will be created
  + resource "statuspal_service" "child" {
      + id                    = (known after apply)
      + service               = {
          + auto_incident                        = (known after apply)
          + auto_notify                          = (known after apply)
          + children_ids                         = (known after apply)
          + current_incident_type                = (known after apply)
          + description                          = (known after apply)
          + display_response_time_chart          = (known after apply)
          + display_uptime_graph                 = (known after apply)
          + id                                   = (known after apply)
          + inbound_email_id                     = (known after apply)
          + incident_type                        = (known after apply)
          + inserted_at                          = (known after apply)
          + is_up                                = (known after apply)
          + monitoring                           = (known after apply)
          + name                                 = "Example Terraform Child Service"
          + order                                = (known after apply)
          + parent_id                            = (known after apply)
          + parent_incident_type                 = (known after apply)
          + pause_monitoring_during_maintenances = (known after apply)
          + ping_url                             = (known after apply)
          + private                              = (known after apply)
          + private_description                  = (known after apply)
          + translations                         = (known after apply)
          + updated_at                           = (known after apply)
        }
      + status_page_subdomain = "example-com"
    }

  # statuspal_service.example will be created
  + resource "statuspal_service" "example" {
      + id                    = (known after apply)
      + service               = {
          + auto_incident                        = (known after apply)
          + auto_notify                          = (known after apply)
          + children_ids                         = (known after apply)
          + current_incident_type                = (known after apply)
          + description                          = (known after apply)
          + display_response_time_chart          = (known after apply)
          + display_uptime_graph                 = (known after apply)
          + id                                   = (known after apply)
          + inbound_email_id                     = (known after apply)
          + incident_type                        = (known after apply)
          + inserted_at                          = (known after apply)
          + is_up                                = (known after apply)
          + monitoring                           = (known after apply)
          + name                                 = "Example Terraform Service"
          + order                                = (known after apply)
          + parent_id                            = (known after apply)
          + parent_incident_type                 = (known after apply)
          + pause_monitoring_during_maintenances = (known after apply)
          + ping_url                             = (known after apply)
          + private                              = (known after apply)
          + private_description                  = (known after apply)
          + translations                         = (known after apply)
          + updated_at                           = (known after apply)
        }
      + status_page_subdomain = "example-com"
    }

Plan: 2 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

In this case, the plan shows you that Terraform will create 2 services when you run terraform apply. Maybe you already noticed, it's possible to create child services also. After verifying the details, execute the plan to provision the service resources in your example status page:

terraform apply

The same procedure is before, you need to write "yes" to approve the changes.

While it's running, Terraform sends logs to your console:

statuspal_service.example: Creating...
statuspal_service.example: Creation complete after 1s [id=placeholder]
statuspal_service.child: Creating...
statuspal_service.child: Creation complete after 0s [id=placeholder]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Again, you can navigate to /admin/status_pages/:status_page_subdomain/services to confirm that Terraform created your new services in your status page.

4. Configure StatusPal monitoring on a service

To configure StatusPal monitoring on a service you will need the change a few attributes. We will use the previously defined service as an example:

resource "statuspal_service" "example" {
  status_page_subdomain = statuspal_status_page.example.status_page.subdomain
  service = {
    name       = "Example Terraform Service"
    monitoring = "internal"                  # <- this means to use the StatusPal monitoring
    ping_url   = "https://www.statuspal.io"  # <- this is the URL to ping in every minute
  }
}

5. Configure 3rd-party monitoring with incoming webhook URL

To configure 3rd-party monitoring with incoming webhook URL on a service you will need the change a few attributes. We will use the previously defined service as an example:

resource "statuspal_service" "example" {
  status_page_subdomain = statuspal_status_page.example.status_page.subdomain
  service = {
    name                             = "Example Terraform Service"
    monitoring                       = "webhook"                   # <- this means to use the incoming webhook monitoring
    webhook_monitoring_service       = "custom-jsonpath"           # <- with this attribute you can the webhook monitoring service
    webhook_custom_jsonpath_settings = {                           # <- this is the settings for custom-jsonpath type of webhook monitoring service
      jsonpath        = "$.status"
      expected_result = "\"up\""
    }
  }
}

output "example_service_incoming_webhook_url" {
  value = statuspal_service.example.service.incoming_webhook_url
}

After applying the plan with terraform apply you will be able to see the incoming webhook URL in the outputs:

Outputs:

example_service_incoming_webhook_url = "https://statuspal.io/api/v2/status_pages/example-com/services/760f4b7f-7bd1-4459-a91f-c07259bb3f39/automate/custom-jsonpath"

If you run into any problems, feel free to hit us up at support@statuspal.io.

Last updated