# Getting started with Terraform and StatusPal status pages

## 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 <a href="#before-you-begin" id="before-you-begin"></a>

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](https://statuspal.io/registrations/new?try=1). Also, you will need to [install the Terraform CLI](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli).

## 1. Bootstrap Terraform and the StatusPal provider

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

```bash
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**:

```hcl
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](https://www.terraform.io/docs/configuration/version-constraints.html) 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 <a href="#configure-the-new-relic-provider" id="configure-the-new-relic-provider"></a>

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:

```hcl
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.

{% hint style="info" %} <mark style="color:blue;">You can also configure the StatusPal provider using</mark> [environment variables](https://registry.terraform.io/providers/statuspal/statuspal/latest/docs#optional)<mark style="color:blue;">. This is a useful way to set default values for your provider configuration.</mark>

<mark style="color:blue;">For more information about configuring the StatusPal provider, please feel free to check out our official provider</mark> [documentation](https://registry.terraform.io/providers/statuspal/statuspal/latest/docs#optional)<mark style="color:blue;">.</mark>
{% endhint %}

With your StatusPal provider configured, initialize Terraform:

```bash
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:

```hcl
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:

```bash
terraform plan
```

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

<pre class="language-bash"><code class="lang-bash"># Example output
------------------------------------------------------------------------
<strong>
</strong><strong>Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
</strong>  + 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.

------------------------------------------------------------------------
</code></pre>

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:

```bash
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:

```bash
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](https://statuspal.io/sessions/new) 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:

```hcl
# 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.

```bash
terraform plan
```

You should see the following output:

```bash
# 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:

```bash
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:

```bash
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:

```hcl
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:

```hcl
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:

```bash
Outputs:

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

{% hint style="info" %}
If you run into any problems, feel free to hit us up at <support@statuspal.io>.
{% endhint %}
