Terraform provider
The monitorable-io/monitorable provider manages servers, the alert
template each server follows, and maintenance mutes from Terraform 1.5 or
later and OpenTofu 1.6 or later. It talks to the same public
API as everything else, with an organization API key.
Install
Section titled “Install”terraform { required_providers { monitorable = { source = "monitorable-io/monitorable" version = "~> 0.1" } }}
provider "monitorable" {}The same required_providers block works with OpenTofu 1.6 or later; run
tofu init.
Authenticate
Section titled “Authenticate”Create a key in the dashboard under Team → API keys and give it these
four scopes: servers:read, servers:write, alerts:read and
alerts:write. The Automation preset covers the server scopes and
alerts:write but not alerts:read, which the monitorable_alert_template,
monitorable_alert_templates and monitorable_notification_channels data
sources need, so choose the four scopes explicitly. API keys and
scopes lists what each scope allows.
Pass the key with an environment variable so no credential appears in the configuration:
export MONITORABLE_API_KEY=<your-api-key>| Setting | Environment variable | Argument | Default |
|---|---|---|---|
| API key | MONITORABLE_API_KEY |
api_key |
none (required) |
| API origin | MONITORABLE_ENDPOINT |
endpoint |
https://api.monitorable.io |
A provider argument wins over the matching environment variable. Set
api_key only from a secret store or a sensitive variable, never as a
literal.
Create a server and install the agent
Section titled “Create a server and install the agent”monitorable_server creates the server record. The API returns the agent’s
key and the install command once, when the server is created; the provider
keeps them as the sensitive attributes agent_api_key and
install_command. Run the command on the host with a remote-exec
provisioner:
resource "monitorable_server" "web" { name = "web-01"}
# Install the agent on the host with the command the API returned when the# server was created. install_command embeds the agent's API key; it is# sensitive, so Terraform hides the provisioner's output.resource "null_resource" "web_agent" { depends_on = [monitorable_server.web]
triggers = { server_id = monitorable_server.web.id }
connection { type = "ssh" host = "203.0.113.10" user = "ubuntu" }
# install_command is null for an imported server (and after a create whose # response was lost and recovered on retry), so this provisioner applies only # to servers this configuration created. For an imported server, rotate the # agent key in the dashboard and install the agent with the new key. provisioner "remote-exec" { inline = [monitorable_server.web.install_command] }}Changing name renames the server in place. Destroying the resource
deletes the server and its metrics history.
Assign an alert template
Section titled “Assign an alert template”A server with no assignment follows the organization’s default template. Look a template up by name and assign it:
# Look the template up by name instead of hard-coding its id.data "monitorable_alert_template" "strict" { name = "Strict"}
# Servers with no assignment follow the organization's default template.# Destroying this resource returns web-01 to that default; the template stays.resource "monitorable_server_alert_template" "web" { server_id = monitorable_server.web.id template_id = data.monitorable_alert_template.strict.id}The name is exact and case-sensitive. Destroying
monitorable_server_alert_template returns the server to the default
template; it never deletes the template. If someone resets the assignment in
the dashboard, the next plan assigns it again.
Mute during a deploy or maintenance
Section titled “Mute during a deploy or maintenance”monitorable_server_mute mutes a server’s alerts. Set until for a window,
or omit it to mute until the resource is destroyed.
# A maintenance window: alerts are muted until the instant passes. After that# the resource stays in state as completed (active = false) and is not applied# again; change `until` to open a new window.resource "monitorable_server_mute" "window" { server_id = monitorable_server.web.id until = "2026-12-01T06:00:00Z" reason = "kernel upgrade"}
# Mute for the duration of one apply, for example from a deploy pipeline.# timestamp() changes on every run, so ignore_changes keeps the mute from being# replaced by the next plan: the window is opened once, when the resource is# created, and `terraform destroy` lifts it early. A pipeline that wants one# window per deploy should drop `ignore_changes`: each apply's timestamp() then# differs from the state's, which replaces the mute and opens a fresh window.resource "monitorable_server_mute" "deploy" { server_id = monitorable_server.web.id until = timeadd(timestamp(), "30m") reason = "deploy"
lifecycle { ignore_changes = [until] }}
# With no `until` the mute lasts until the resource is destroyed.resource "monitorable_server_mute" "until_destroyed" { server_id = monitorable_server.web.id reason = "decommissioning"}A mute whose until has passed stays in state as completed and is not
applied again. Changing until to another instant replaces the resource
and opens a new window. Destroying the resource unmutes the server. A
server has at most one mute.
Import an existing server
Section titled “Import an existing server”Adopt a server that already exists, whether you added it in the dashboard or an apply left it behind (see Interrupted applies):
terraform import monitorable_server.web 42The id is the server’s id, which data "monitorable_servers" returns. The
alert template assignment and the mute import the same way, by server id:
terraform import monitorable_server_alert_template.web 42terraform import monitorable_server_mute.window 42A server that follows the default template has no assignment to import, and
a server that is not muted has no mute to import. An imported server has no
agent_api_key or install_command, because the API returns them only when
the server is created. To install the agent on it, rotate its key in the
dashboard.
Data sources
Section titled “Data sources”| Data source | Returns |
|---|---|
monitorable_server |
One server, by id or by exact, case-sensitive name. |
monitorable_servers |
Servers, optionally filtered with name_contains and status. |
monitorable_alert_template |
One alert template, by name. |
monitorable_alert_templates |
All alert templates, with which one is the default. |
monitorable_notification_channels |
The organization’s notification channels; their settings are never exposed. |
Autoscaling groups and images
Section titled “Autoscaling groups and images”monitorable_server suits a known, named set of machines. When servers
appear without Terraform creating each one, such as autoscaling groups and
machine images, use an enrollment key instead: each host registers itself
when it boots. See Add servers without the
dashboard.
Interrupted applies
Section titled “Interrupted applies”If an apply is killed or interrupted after the API created a server, or its
retries ran out, the server can exist without Terraform tracking it. Find it
with data "monitorable_servers" or in the dashboard and adopt it with
terraform import monitorable_server.<name> <id>. Running the apply again
without importing would try to create a second server.
The state holds the agent key
Section titled “The state holds the agent key”agent_api_key and install_command are marked sensitive, which hides them
from plan and apply output, but Terraform still stores them in state in plain
text. Treat the state as a secret: use an encrypted remote backend with
restricted access and never commit it. If a state file is exposed, rotate the
server’s agent key in the dashboard.
Limits
Section titled “Limits”- Plan limit. When the plan’s server limit is reached, creating a server
fails with a
402plan_limit_reachederror that says where to raise the limit. Remove a server or upgrade; see pricing for the plans. - Rate limits. Writes are limited to 60 per minute per API key. The
provider waits and retries when the API answers
429, so Terraform’s default-parallelism=10is fine. See Rate limits and retries and Errors.