Skip to content

Manage a fleet of clusters with hub and spoke portals

When you finish, two spoke clusters present the hub cluster's /data directory, and clients mount /data over NFS from whichever cluster is closest.

Before you start

  • A hub cluster and two spoke clusters, each with a REST API on port 8000 that you can reach from this machine
  • An admin account on each cluster for its connection profile
  • Port 3713 open in both directions between the hub and every spoke
  • The directory to share on the hub, /data in the example
  • Terraform 1.11 or later

1. Copy the configuration

Save this as main.tf in an empty directory.

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" {
  connection_profiles = [
    {
      name                 = "hub"
      endpoint             = "https://hub.example.com:8000" # <-- Replace with the hub's REST API endpoint
      username             = "admin"
      password             = "HubPassword123!" # <-- Replace with the hub's admin password
      insecure_skip_verify = true
    },
    {
      name                 = "us-west"
      endpoint             = "https://us-west.example.com:8000" # <-- Replace with this spoke's REST API endpoint
      username             = "admin"
      password             = "UsWestPassword123!" # <-- Replace with this spoke's admin password
      insecure_skip_verify = true
    },
    {
      name                 = "eu-west"
      endpoint             = "https://eu-west.example.com:8000" # <-- Replace with this spoke's REST API endpoint
      username             = "admin"
      password             = "EuWestPassword123!" # <-- Replace with this spoke's admin password
      insecure_skip_verify = true
    },
  ]
}

locals {
  hub_address = "10.0.0.10" # <-- Replace with a hub address the spokes can reach

  spoke_addresses = {
    us-west = "10.1.0.10" # <-- Replace with an address the hub can reach
    eu-west = "10.2.0.10" # <-- Replace with an address the hub can reach
  }
}

resource "qumulo_portal" "fleet" {
  for_each = local.spoke_addresses

  hub_connection_profile   = "hub"
  spoke_connection_profile = each.key

  type        = "PORTAL_READ_WRITE"
  hub_hosts   = [local.hub_address]
  spoke_hosts = [each.value]
}

resource "qumulo_portal_root" "fleet" {
  for_each = local.spoke_addresses

  portal_id       = qumulo_portal.fleet[each.key].id
  hub_root_path   = "/data"
  spoke_root_path = "/cache"
}

resource "qumulo_nfs_export" "hub" {
  connection_profile = "hub"

  export_path = "/data"
  fs_path     = "/data"
  description = "Fleet data (hub)"
}

resource "qumulo_nfs_export" "spokes" {
  for_each = local.spoke_addresses

  connection_profile = each.key

  export_path = "/data"
  fs_path     = "/cache"
  description = "Fleet data (${each.key})"

  depends_on = [qumulo_portal_root.fleet]
}

output "portal_states" {
  value = {
    for name, portal in qumulo_portal.fleet : name => {
      hub_state  = portal.hub_state
      hub_status = portal.hub_status
    }
  }
}

Replace the nine values marked <-- Replace, and leave the rest as written. The hub address must be reachable from every spoke, and each spoke address from the hub.

Delete each insecure_skip_verify whose cluster has a certificate signed by a CA your machine trusts.

Each spoke shows the hub's /data at /cache, and every cluster exports its copy as /data, so clients see one path everywhere.

  • For spokes that should only read, set type = "PORTAL_READ_ONLY". Read-write spokes send their writes back to the hub.
  • To serve the same data over SMB, add a qumulo_smb_share beside each export, as in SMB shares.

2. Apply

terraform init -upgrade
terraform plan
terraform apply

The plan ends with Plan: 7 to add, 0 to change, 0 to destroy. The apply ends with Apply complete! Resources: 7 added, 0 changed, 0 destroyed., followed by the portal_states output.

3. Check the portals

The portal_states output shows hub_state = "ACCEPTED" and hub_status = "ACTIVE" for each spoke. A DEGRADED status means the clusters connect only partly, so check port 3713 between them.

4. Add a spoke

Add a connection profile for the new cluster, then add an entry with the same name to spoke_addresses.

    ap-east = "10.3.0.10" # <-- Replace with an address the hub can reach

Run terraform apply. The plan ends with Plan: 3 to add, 0 to change, 0 to destroy., covering the new spoke's portal, root, and export.

5. Remove a spoke

Delete the spoke's entry from spoke_addresses and run terraform apply. The plan ends with Plan: 0 to add, 0 to change, 3 to destroy.

After the apply, delete the spoke's connection profile as well. Terraform needs the profile to reach the spoke while it destroys the portal, root, and export.

Next

Cloud Data Fabric concepts, including how portal creation works, are in Qumulo's documentation. If a portal stays PENDING, see Troubleshoot cluster configuration, and the qumulo_portal reference lists every attribute.