Cluster

The appliances that share this configuration. A cluster has one primary; the others follow it and can take over.

Get the cluster status

GET /cluster

Returns the status of the cluster.

curl
curl -X GET "https://appliance.example.com/api/v1/cluster" \
  -H "Authorization: Bearer $TOKEN"
PHP
<?php

$url = 'https://appliance.example.com/api/v1/cluster';
$headers = [
    'Authorization: Bearer ' . $token,
];

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_RETURNTRANSFER => true,
]);

$response = json_decode(curl_exec($ch), true);
curl_close($ch);
Python
import requests

headers = {"Authorization": f"Bearer {token}"}

response = requests.get("https://appliance.example.com/api/v1/cluster", headers=headers)
response.raise_for_status()
print(response.json())
JavaScript
const response = await fetch('https://appliance.example.com/api/v1/cluster', {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${token}`,
  },
});

const data = await response.json();
Response
{
  "status": "success",
  "message": "Cluster status",
  "data": []
}

Join this appliance to a cluster

POST /cluster/join

Pair a node into the cluster

This change is staged. Send PUT /services/apply to apply it.

Body parameters
ip string Required
email string Required
password string Required
port string Required
curl
curl -X POST "https://appliance.example.com/api/v1/cluster/join" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "ip": "<ip>",
  "email": "<email>",
  "password": "<password>",
  "port": "<port>"
}'
PHP
<?php

$url = 'https://appliance.example.com/api/v1/cluster/join';
$headers = [
    'Authorization: Bearer ' . $token,
    'Content-Type: application/json',
];

$payload = [
    'ip' => '<ip>',
    'email' => '<email>',
    'password' => '<password>',
    'port' => '<port>',
];

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POSTFIELDS => json_encode($payload),
]);

$response = json_decode(curl_exec($ch), true);
curl_close($ch);
Python
import requests

headers = {"Authorization": f"Bearer {token}"}
payload = {
    "ip": "<ip>",
    "email": "<email>",
    "password": "<password>",
    "port": "<port>"
}

response = requests.post("https://appliance.example.com/api/v1/cluster/join", headers=headers, json=payload)
response.raise_for_status()
print(response.json())
JavaScript
const response = await fetch('https://appliance.example.com/api/v1/cluster/join', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${token}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
  "ip": "<ip>",
  "email": "<email>",
  "password": "<password>",
  "port": "<port>"
}),
});

const data = await response.json();
Response
{
  "status": "success",
  "message": "Cluster successfully configured.",
  "data": {
    "id": "123-456-789-ab0",
    "unmatchedNetworks": []
  }
}

Promote a node to primary

GET /cluster/promote/{id}

Promote a node in the cluster

Path parameters
id string Required
curl
curl -X GET "https://appliance.example.com/api/v1/cluster/promote/{id}" \
  -H "Authorization: Bearer $TOKEN"
PHP
<?php

$url = 'https://appliance.example.com/api/v1/cluster/promote/{id}';
$headers = [
    'Authorization: Bearer ' . $token,
];

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_RETURNTRANSFER => true,
]);

$response = json_decode(curl_exec($ch), true);
curl_close($ch);
Python
import requests

headers = {"Authorization": f"Bearer {token}"}

response = requests.get("https://appliance.example.com/api/v1/cluster/promote/{id}", headers=headers)
response.raise_for_status()
print(response.json())
JavaScript
const response = await fetch('https://appliance.example.com/api/v1/cluster/promote/{id}', {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${token}`,
  },
});

const data = await response.json();
Response
{
  "status": "success",
  "message": "Node id: {id} was promoted",
  "data": {
    "id": "123-456-789-ab0"
  }
}

Pull configuration from every node in the cluster

PUT /cluster/pull

Pull section data from all Nodes in the Cluster

This change is staged. Send PUT /services/apply to apply it.

curl
curl -X PUT "https://appliance.example.com/api/v1/cluster/pull" \
  -H "Authorization: Bearer $TOKEN"
PHP
<?php

$url = 'https://appliance.example.com/api/v1/cluster/pull';
$headers = [
    'Authorization: Bearer ' . $token,
];

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PUT',
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_RETURNTRANSFER => true,
]);

$response = json_decode(curl_exec($ch), true);
curl_close($ch);
Python
import requests

headers = {"Authorization": f"Bearer {token}"}

response = requests.put("https://appliance.example.com/api/v1/cluster/pull", headers=headers)
response.raise_for_status()
print(response.json())
JavaScript
const response = await fetch('https://appliance.example.com/api/v1/cluster/pull', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${token}`,
  },
});

const data = await response.json();
Response
{
  "status": "success",
  "message": "Cluster pull complete",
  "data": []
}

Pull configuration from a node

PUT /cluster/pull/{id}

Pull section data from a Node in the Cluster

This change is staged. Send PUT /services/apply to apply it.

Path parameters
id string Required

Node UUID

curl
curl -X PUT "https://appliance.example.com/api/v1/cluster/pull/{id}" \
  -H "Authorization: Bearer $TOKEN"
PHP
<?php

$url = 'https://appliance.example.com/api/v1/cluster/pull/{id}';
$headers = [
    'Authorization: Bearer ' . $token,
];

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PUT',
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_RETURNTRANSFER => true,
]);

$response = json_decode(curl_exec($ch), true);
curl_close($ch);
Python
import requests

headers = {"Authorization": f"Bearer {token}"}

response = requests.put("https://appliance.example.com/api/v1/cluster/pull/{id}", headers=headers)
response.raise_for_status()
print(response.json())
JavaScript
const response = await fetch('https://appliance.example.com/api/v1/cluster/pull/{id}', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${token}`,
  },
});

const data = await response.json();
Response
{
  "status": "success",
  "message": "Node pull complete",
  "data": []
}

Restore a node into the cluster

POST /cluster/restore

This change is staged. Send PUT /services/apply to apply it.

Body parameters
ip string Required
email string Required
password string Required
port string Required
restoreNode string Required
curl
curl -X POST "https://appliance.example.com/api/v1/cluster/restore" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "ip": "<ip>",
  "email": "<email>",
  "password": "<password>",
  "port": "<port>",
  "restoreNode": "<restoreNode>"
}'
PHP
<?php

$url = 'https://appliance.example.com/api/v1/cluster/restore';
$headers = [
    'Authorization: Bearer ' . $token,
    'Content-Type: application/json',
];

$payload = [
    'ip' => '<ip>',
    'email' => '<email>',
    'password' => '<password>',
    'port' => '<port>',
    'restoreNode' => '<restoreNode>',
];

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POSTFIELDS => json_encode($payload),
]);

$response = json_decode(curl_exec($ch), true);
curl_close($ch);
Python
import requests

headers = {"Authorization": f"Bearer {token}"}
payload = {
    "ip": "<ip>",
    "email": "<email>",
    "password": "<password>",
    "port": "<port>",
    "restoreNode": "<restoreNode>"
}

response = requests.post("https://appliance.example.com/api/v1/cluster/restore", headers=headers, json=payload)
response.raise_for_status()
print(response.json())
JavaScript
const response = await fetch('https://appliance.example.com/api/v1/cluster/restore', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${token}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
  "ip": "<ip>",
  "email": "<email>",
  "password": "<password>",
  "port": "<port>",
  "restoreNode": "<restoreNode>"
}),
});

const data = await response.json();
Response
{
  "status": "success",
  "message": "Cluster successfully restored.",
  "data": {
    "id": "123-456-789-ab0",
    "unmatchedNetworks": []
  }
}

Resynchronise every node in the cluster

PUT /cluster/resync

Sync all nodes in the cluster

This change is staged. Send PUT /services/apply to apply it.

curl
curl -X PUT "https://appliance.example.com/api/v1/cluster/resync" \
  -H "Authorization: Bearer $TOKEN"
PHP
<?php

$url = 'https://appliance.example.com/api/v1/cluster/resync';
$headers = [
    'Authorization: Bearer ' . $token,
];

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PUT',
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_RETURNTRANSFER => true,
]);

$response = json_decode(curl_exec($ch), true);
curl_close($ch);
Python
import requests

headers = {"Authorization": f"Bearer {token}"}

response = requests.put("https://appliance.example.com/api/v1/cluster/resync", headers=headers)
response.raise_for_status()
print(response.json())
JavaScript
const response = await fetch('https://appliance.example.com/api/v1/cluster/resync', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${token}`,
  },
});

const data = await response.json();
Response
{
  "status": "success",
  "message": "Cluster resync successful!",
  "data": []
}

Resynchronise a node

PUT /cluster/resync/{id}

Sync a nodes in the cluster

This change is staged. Send PUT /services/apply to apply it.

Path parameters
id string Required

The id of the resync.

curl
curl -X PUT "https://appliance.example.com/api/v1/cluster/resync/{id}" \
  -H "Authorization: Bearer $TOKEN"
PHP
<?php

$url = 'https://appliance.example.com/api/v1/cluster/resync/{id}';
$headers = [
    'Authorization: Bearer ' . $token,
];

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PUT',
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_RETURNTRANSFER => true,
]);

$response = json_decode(curl_exec($ch), true);
curl_close($ch);
Python
import requests

headers = {"Authorization": f"Bearer {token}"}

response = requests.put("https://appliance.example.com/api/v1/cluster/resync/{id}", headers=headers)
response.raise_for_status()
print(response.json())
JavaScript
const response = await fetch('https://appliance.example.com/api/v1/cluster/resync/{id}', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${token}`,
  },
});

const data = await response.json();
Response
{
  "status": "success",
  "message": "Cluster resync successful!",
  "data": []
}

Get the cluster synchronisation status

GET /cluster/sync-status

Cluster-aware diff of every section across all reporting Nodes. For each section, Config Data is compared by N-way plurality consensus: the uniquely largest group of matching nodes is the majority and the rest are outliers; a tie for the largest group is reported as "no_majority" and is never auto-resolved. Node Data is owner-anchored: each peer’s replica is compared against the owning node’s authoritative hash, and mismatches are reported as stale replicas (repaired by a pull, not a push). Unreachable nodes are listed in "nodesUnreachable" and excluded from consensus. The diff is read-only.

curl
curl -X GET "https://appliance.example.com/api/v1/cluster/sync-status" \
  -H "Authorization: Bearer $TOKEN"
PHP
<?php

$url = 'https://appliance.example.com/api/v1/cluster/sync-status';
$headers = [
    'Authorization: Bearer ' . $token,
];

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_RETURNTRANSFER => true,
]);

$response = json_decode(curl_exec($ch), true);
curl_close($ch);
Python
import requests

headers = {"Authorization": f"Bearer {token}"}

response = requests.get("https://appliance.example.com/api/v1/cluster/sync-status", headers=headers)
response.raise_for_status()
print(response.json())
JavaScript
const response = await fetch('https://appliance.example.com/api/v1/cluster/sync-status', {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${token}`,
  },
});

const data = await response.json();
Response
{
  "status": "success",
  "message": "Current Status",
  "data": {
    "inSync": false,
    "nodesReporting": [
      "node-a",
      "node-b",
      "node-c"
    ],
    "nodesUnreachable": [],
    "sections": {
      "haproxy": {
        "config": {
          "resolution": "outliers",
          "groups": [
            {
              "hash": "abc123",
              "nodeIds": [
                "node-a",
                "node-b"
              ],
              "changes": 4
            },
            {
              "hash": "def456",
              "nodeIds": [
                "node-c"
              ],
              "changes": 5
            }
          ],
          "majorityHash": "abc123",
          "outlierNodeIds": [
            "node-c"
          ],
          "dataDiff": {
            "node-c": {
              "timeout": {
                "majority": 5000,
                "outlier": 8000
              }
            }
          }
        },
        "nodeData": {
          "resolution": "stale_replicas",
          "owners": [
            {
              "ownerId": "node-c",
              "ownerHash": "h-c",
              "staleReplicas": [
                {
                  "nodeId": "node-a",
                  "replicaHash": "h-c-old"
                }
              ]
            }
          ]
        }
      }
    }
  }
}

Remove a node from the cluster

DELETE /cluster/{id}

Delete a node in the cluster

This change is staged. Send PUT /services/apply to apply it.

Path parameters
id string Required

.Query parameters

interfaceName string

Ethernet interface to keep reachable with a static IP after the node resets. When omitted, all interfaces reset to DHCP (default behaviour). Must name a physical Ethernet interface (bonds/VLANs are torn down by the reset).

ipv4Address string

Static IPv4 address for the interface.

ipv4Netmask string

IPv4 prefix length (0-32). Required with ipv4Address.

ipv4Gateway string

Optional IPv4 gateway.

ipv4Dns string

Optional IPv4 DNS server.

ipv6Address string

Static IPv6 address for the interface.

ipv6Netmask string

IPv6 prefix length (0-128). Required with ipv6Address.

ipv6Gateway string

Optional IPv6 gateway.

ipv6Dns string

Optional IPv6 DNS server.

curl
curl -X DELETE "https://appliance.example.com/api/v1/cluster/{id}" \
  -H "Authorization: Bearer $TOKEN"
PHP
<?php

$url = 'https://appliance.example.com/api/v1/cluster/{id}';
$headers = [
    'Authorization: Bearer ' . $token,
];

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'DELETE',
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_RETURNTRANSFER => true,
]);

$response = json_decode(curl_exec($ch), true);
curl_close($ch);
Python
import requests

headers = {"Authorization": f"Bearer {token}"}

response = requests.delete("https://appliance.example.com/api/v1/cluster/{id}", headers=headers)
response.raise_for_status()
print(response.json())
JavaScript
const response = await fetch('https://appliance.example.com/api/v1/cluster/{id}', {
  method: 'DELETE',
  headers: {
    Authorization: `Bearer ${token}`,
  },
});

const data = await response.json();
Response
{
  "status": "success",
  "message": "Cluster node {id} removed",
  "data": []
}

Put a node into maintenance

PUT /cluster/{id}/maintenance

Enable maintenance mode on a Cluster Node

This change is staged. Send PUT /services/apply to apply it.

Path parameters
id string Required

Node UUID

curl
curl -X PUT "https://appliance.example.com/api/v1/cluster/{id}/maintenance" \
  -H "Authorization: Bearer $TOKEN"
PHP
<?php

$url = 'https://appliance.example.com/api/v1/cluster/{id}/maintenance';
$headers = [
    'Authorization: Bearer ' . $token,
];

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PUT',
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_RETURNTRANSFER => true,
]);

$response = json_decode(curl_exec($ch), true);
curl_close($ch);
Python
import requests

headers = {"Authorization": f"Bearer {token}"}

response = requests.put("https://appliance.example.com/api/v1/cluster/{id}/maintenance", headers=headers)
response.raise_for_status()
print(response.json())
JavaScript
const response = await fetch('https://appliance.example.com/api/v1/cluster/{id}/maintenance', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${token}`,
  },
});

const data = await response.json();
Response
{
  "status": "success",
  "message": "Node {id} maintenance mode enabled",
  "data": []
}

Take a node out of maintenance

PUT /cluster/{id}/maintenance/disable

Disable maintenance mode on a Cluster Node

This change is staged. Send PUT /services/apply to apply it.

Path parameters
id string Required

Node UUID

curl
curl -X PUT "https://appliance.example.com/api/v1/cluster/{id}/maintenance/disable" \
  -H "Authorization: Bearer $TOKEN"
PHP
<?php

$url = 'https://appliance.example.com/api/v1/cluster/{id}/maintenance/disable';
$headers = [
    'Authorization: Bearer ' . $token,
];

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PUT',
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_RETURNTRANSFER => true,
]);

$response = json_decode(curl_exec($ch), true);
curl_close($ch);
Python
import requests

headers = {"Authorization": f"Bearer {token}"}

response = requests.put("https://appliance.example.com/api/v1/cluster/{id}/maintenance/disable", headers=headers)
response.raise_for_status()
print(response.json())
JavaScript
const response = await fetch('https://appliance.example.com/api/v1/cluster/{id}/maintenance/disable', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${token}`,
  },
});

const data = await response.json();
Response
{
  "status": "success",
  "message": "Node {id} maintenance mode disabled",
  "data": []
}