Skip to content

Run your own scripts during cluster boot

When you finish, your own shell runs inside the cluster's boot scripts, and every node and provisioner run picks up your proxy, CA, agent, or notification. The node_hooks and provisioner_hooks attributes work the same way on qumulo_filesystem_aws, qumulo_filesystem_azure, and qumulo_filesystem_gcp.

Before you start

1. Pick the anchor

  • To prepare each node before it touches the network (proxy, CA, package mirror), use node_hooks.pre_run.
  • To add software to each node after qumulo-core is installed (monitoring agent), use node_hooks.post_run.
  • To prepare the provisioner before it touches the network (proxy, mirror), use provisioner_hooks.pre_run.
  • To act once the cluster is formed and configured (notification, CMDB record), use provisioner_hooks.post_run.

You now know which of the four fields each script belongs in.

2. Write the hook

Check every hook against this list.

  • Make each command succeed, or end it in || true where failure is acceptable.
  • Keep secrets out. Fetch credentials from the instance's IAM role, managed identity, service account, or a cloud secret store.
  • Make a second run harmless.
  • Run shellcheck on the script.
  • Use only the image's stock commands in pre_run, and move anything that needs the cloud CLI or jq to post_run.

The hook passes all five, and shellcheck prints nothing. The shell variables a hook can read are listed in Shell variables available to boot hooks.

3. Add it to the configuration

This AWS configuration wires all four hooks inline. Each field is a plain string, so file("${path.module}/hooks/notify.sh") works in place of any heredoc.

terraform {
  required_version = ">= 1.11"
  required_providers {
    qumulo = {
      source  = "qumulo-terraform-registry.s3.us-east-1.amazonaws.com/qumulo/qumulo"
      version = "~> 1.0"
    }
  }
}

provider "qumulo" {
  aws {}
}

resource "qumulo_filesystem_aws" "cluster" {
  cluster_name         = "qumulo"
  deployment_name      = "qumulo"
  region               = "us-east-1"                  # <-- Replace with your region
  subnet_ids           = ["subnet-0123456789abcdef0"] # <-- Replace with your subnet ID
  node_count           = 3
  instance_type        = "m6idn.2xlarge"
  cluster_product_type = "HOT"
  admin_password       = "YourSecurePassword123!" # <-- Replace with your admin password
  allow_cidrs          = ["10.0.0.0/8"]           # <-- Replace with your client networks
  deletion_protection  = true

  node_hooks = {
    pre_run = <<-EOT
      export http_proxy="http://proxy.corp.example.com:3128" # <-- Replace with your proxy
      export https_proxy="$http_proxy"
      echo "Acquire::http::Proxy \"$http_proxy\";" > /etc/apt/apt.conf.d/95corp-proxy
      cp /opt/corp/ca/corp-root.crt /usr/local/share/ca-certificates/ && update-ca-certificates
    EOT

    post_run = <<-EOT
      curl -fsSL "https://agent.corp.example.com/install.sh" | bash # <-- Replace with your agent installer
    EOT
  }

  provisioner_hooks = {
    pre_run = <<-EOT
      export https_proxy="http://proxy.corp.example.com:3128" # <-- Replace with your proxy
      export no_proxy="169.254.169.254,localhost,127.0.0.1"
    EOT

    post_run = <<-EOT
      curl -fsS -X POST "https://cmdb.corp.example.com/api/clusters" \
        -H "Content-Type: application/json" \
        -d "{\"deployment\":\"$deployment_name\",\"status\":\"ready\"}" # <-- Replace with your tracker
    EOT
  }

  timeouts {
    create = "90m"
  }
}

output "endpoint_ips" {
  value = qumulo_filesystem_aws.cluster.endpoint_ips
}

Replace the values marked <-- Replace. Inside a heredoc, write shell variables as $name, since Terraform claims ${...} for its own interpolation.

On Azure or GCP, copy the node_hooks and provisioner_hooks blocks into your qumulo_filesystem_azure or qumulo_filesystem_gcp resource. terraform validate prints Success! The configuration is valid.

4. Apply

terraform plan
terraform apply

For a new cluster the plan ends with Plan: 1 to add, 0 to change, 0 to destroy., and every hook runs during the create. On an existing cluster the plan shows Plan: 0 to add, 1 to change, 0 to destroy., and the new hooks run at the next provisioner launch (scaling, node replacement, storage updates) or the next new node's first boot, never on running instances.

5. Check the hook ran

Every hook line is traced into the boot log with a leading +. Sign in to a node and search that log for a command from your hook.

sudo grep -n 'proxy.corp.example.com' /var/log/user-data.log
sudo grep -n 'proxy.corp.example.com' /var/log/startup-script.log

The search prints your hook's lines, and /var/lib/qumulo-node/bootstrap-complete exists once the node script has finished, post_run included. Provisioner hooks log to CloudWatch Logs under /qumulo/<deployment>/provisioner on AWS, to cloud-init output on Azure, and to Cloud Logging and the serial console on GCP.

Warning

A failing provisioner_hooks.pre_run on AWS or Azure cannot report itself, and terraform apply waits out its full timeout. Read the provisioner's boot log instead of waiting.

Next

Every variable a hook can read is listed in Shell variables available to boot hooks. To confirm a hook ran on a node, see SSH to a node.