API Reference

This document describes the Application Programming Interface (API) for interacting with Scyld ClusterWare.

Overview

The Scyld ClusterWare API enables cluster management, monitoring, and provisioning using a series of HTTP requests. While this web API is typically accessed by using the provided web portal and command line tools, users can also create their own customized tools by calling the web API in their own scripts.

Aside from a couple of endpoints related to long-running background jobs, the ClusterWare API is stateless, meaning there is no need for the client to remember any previous state information.

The API is organized around the major ClusterWare objects:

  • Nodes - /nodes

  • Attribute Groups - /attribs

  • Admins - /admins

  • Login/Authentication endpoints

  • Boot Configurations - /bootconfigs

  • Images - /images

  • Networks - /nets

  • Hostnames - /hosts

  • Dynamic Groups - /dyngroups

  • Naming Pools - /namingpools

  • Head nodes - /heads, /database

  • Software Repositories - /repos

  • Software Distributions - /distros

  • Git Repositories - /gitrepos

  • Cluster-wide information - /cluster

Each ClusterWare object type has several method endpoints for getting or setting data that can be accessed using an HTTP call to the correct endpoint. For example, an HTTP GET call to the /nodes endpoint will return a list of all known nodes.

Some method endpoints also accept a unique identifier (UID) as part of the URL. For example, an HTTP GET call to /node/<UID> will return details about the node with the matching UID. A UID is a 32-character string of lower-case letters and digits, such as bf0f61d24ce84064a8c7c7e872332c07 or e54e420c42214101918584e27382e8f5.

Many method endpoints that accept a UID will also accept other identifiers in place of a UID. For example, calls to Admins endpoints can use a username in place of the UID and calls to the Nodes endpoints can accept a node name, MAC address, or IP address in place of the UID.

Data being sent to web API endpoints is expected to be encoded in JSON format. Usually this data will be an JSON object (hash-table or dictionary), though some endpoints accept a list or string instead.

The HTTP response from the server will usually be a JSON object. When an HTTP request is successful, the response will have an HTTP status code of 200, the JSON object will contain a "success" entry with a value of true, and any additional data can be found in the "data" entry. For example:

{ "success": true, "data": "4e75fa48…0f005bd" }

If the HTTP response fails, then a 400-series status code will be returned (e.g. 401 for invalid credentials; 403 for denied access; 404 for object not found, etc.), the "success" entry will have a value of false, and a "reason" entry will have a description of why the action failed. For example:

{ “success":  false, "reason": "No node found for ID=n123" }

Authentication

The majority of ClusterWare API endpoints require that an authentication token is included in the request. This authentication token will usually come from a call to the login or token refresh endpoints. There are several authentication options for logging in:

  • Username / Password authentication. This leverages the operating system's login credentials.

  • SSH key authentication. This uses a public / private key pair. The private keys must be set inside ClusterWare.

  • Local-socket authentication service. This only works if a user is logged in to the head node where the request is made.

When the login is successful, two JSON Web Tokens (JWTs; see https://jwt.io/) will be returned: an access token and a refresh token. The refresh token can be presented to the token-refresh endpoint to make a new access token.

Note

The ClusterWare command-line tools use the access token when possible and will automatically use the refresh token when the access token has expired. Admins writing their own tools will have to detect errors due to token expiration and manually initiate a refresh.

While there are ways to unpack and interpret the data inside a JWT, the tokens can be considered opaque. A client simply receives a JWT upon login, and then sends that same JWT inside an authorization header on future requests:

Header:  “Authorization:  Bearer  eyJhbGciOiJIUzI1Ni…”

The access token has an embedded expiration time (which is also sent by ClusterWare during the login process) and after that time, the token will be rejected by the head node. The refresh token has its own expiration time, usually much longer than the access token. So the expectation is that when the access token expires, the refresh token will still be valid and can be used to make a new access token.

Note

While the refresh token is ONLY usable for making a new access token, it cannot be used to interact with the other endpoints.

In a multi-head cluster, every head node may be configured to use different underlying “secrets” that are used when making new tokens. Thus, after authenticating to one head node, the tokens that are returned may not be usable on other head nodes. In the rare case that a client needs to interact with multiple head nodes, it should login to each one separately and ensure that future requests use the correct token with each corresponding head node.

Where authentication asserts that “this user is who they say they are”, ClusterWare uses role-based access control (RBAC) to limit what specific actions a given user can take. For more information on ClusterWare’s RBAC roles, see sections in the ClusterWare Admin and Reference Guides.

Note

As with other token-based authentication systems, if anyone intercepts or acquires a copy of a token, they can fully impersonate the user who created it. Care must be taken to protect the tokens from other users. Consider using OS or file-system based access control mechanisms.

Username/Password Authentication

The traditional username/password process is provided through a PAM connector. When a login request is made, the system is queried to see if the given username and password are valid. If they are, ClusterWare will make a new token and return it to the caller.

The data is sent as a JSON object with "user" and "pass" keys:

curl -X POST https://head1.cluster.local/api/v1/login --data '{"user":"admin1", \
    "pass":"password"}'

Note that these example curl commands are interacting with an HTTP endpoint, but they are also available using HTTPS. Further, the examples may show passwords on the command line, but putting a password on the command line is not recommended as it may be visible to other users via ps or similar commands.

The returned value will include the access and refresh tokens, as well as expiration values for both:

{"success": true, "data": {"user": "admin1", "token": {"access_token": \
    "eyJhbGciOiJIUzI1Ni…", "expires_in": 1200, "refresh_token": \
    "eyJhbGciOiJIUzI1Ni…", "refresh_expires_in": 2592000}}}

The expiration times are in seconds from when the server issued the token. For long-running actions or scripts, admins may want to err on the side of caution and refresh prior to the actual expiration of the access token.

Note

While the head nodes synchronize data amongst themselves, the underlying operating systems do not synchronize unless configured to do so via some other mechanism. The head nodes could have their /etc/passwd and /etc/shadow files synchronized through scp or sftp, or through an external directory system (LDAP, NIS), but that is outside the scope of this document.

Token Refresh

The access token can be used in subsequent requests up until the expiration time. Once it has expired, the refresh token can be used to acquire a new access token through the token-refresh endpoint:

curl -X GET https://head1.cluster.local/api/v1/newtoken -H "Authorization: \
    Bearer eyJhbGciOiJIUzI1Ni…"

Again, note that this should be the refresh token that is sent to this endpoint – sending an access token will result in a failure.

Upon success, a new set of tokens will be returned:

{"success": true, "data": {"authorized_by": "admin1", "userid": "admin1", "uid": \
    "735367a122664db8ae8ba3ec113f1643", "token": {"access_token": \
    "eyJhbGciOiJIUzI1Ni…", "expires_in": 1200, "refresh_token": \
    "eyJhbGciOiJIUzI1Ni…", "refresh_expires_in": 2592000}}}

If the authentication fails, the "success" field will be false and a "reason" field will contain more information.

Note

The default access token duration is 20 minutes; the default refresh token duration is 30 days.

Alternate Authentication Methods

There are two other authentication methods that can be used during login – a one-time password (OTP) sent to a local socket, and SSH-key authentication. For more information, please contact Penguin Solutions.

Since head nodes are assumed to be “locked down” and protected from end-user access, when a client is running on the head node, they can send an OTP to a known Unix socket and then re-send that OTP during the login process. The same POST /login endpoint is used, but with “user” and “secret” keys. If successful, ClusterWare will return a set of access and refresh tokens.

For information on the SSH-key login process, please contact Penguin Solutions.

Basic Operations

For most ClusterWare objects, standard HTTP actions are supported for manipulating the entries. Using the Node objects as an example:

  • List objects - GET /nodes

  • Create new object - POST /nodes

  • Get object info - GET /node/<UID>

  • Update some info - PATCH /node/<UID>

  • Update all info - PUT /node/<UID>

  • Delete object - DELETE /node/<UID>

  • Metadata - GET /nodes/meta

Endpoints that refer to a whole class of objects are pluralized (end with ‘s’), such as /nodes or /images. Endpoints that refer to one specific object are singular and include a UID, such as /node/<UID> or /image/<UID>.

List Objects

Issuing an HTTP GET to an object-class (pluralized) endpoint will return information about all the objects of that class. Since this endpoint will only return a list of UIDs for the objects, any detailed information will have to be found with a subsequent call to the GET endpoint.

The return value will be a JSON object with two main fields: success and data. The data field will also be a JSON object, with the keys being set to object UIDs:

{ “success":  true, "data":  { "7ad57…73e4a1f4": {… first object’s data …}, \
    "ab89c…2501817": {… second object’s data …}}}

If the request is unsuccessful, then a reason field will be returned with more information on why the request failed.

{ "success":  false, "reason": "No node found for ID=n123" }

Create New Object

To create a new object, a POST is issued to the object-class (pluralized) endpoint with the relevant data. Most object types accept a name and "description" field, but most fields are object-specific (see below for details).

To create a new compute-node object:

curl -X POST https://head1.cluster.local/api/v1/nodes --data \
    '{"mac":"11:22:33:44:55:66"}' -H "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"

On success, ClusterWare will return a UID for the newly create node:

{ “success": true, "data": "4e75fa48…0f005bd" }

Upon failure, the returned data will include a "reason" field with more information on why the request failed:

{ “success": false, "reason": "Node with MAC=52:54:00:00:00:03 already exists." }

Get Object Info

Issuing an HTTP GET to an endpoint will return information about a specific object. Depending on the object type, the UID may be the true UID for the object, the name of the object, or some other object-specific unique identifier such as MAC address (for nodes).

The return value will be a JSON object with two main fields, success and data. The data field will also be a JSON object with a single key-value pair. The key will usually be the object’s UID, but if the request was made with the object’s name, then the key will also be the name.

{ "success":  true, "data":  { "7ad57…73e4a1f4": { … object data … }}}

By default, GET operations will return all of the object’s information: the UID, the name, and all object-specific fields and sub-fields. The client is expected to provide any filtering of data that might be needed.

If the request is unsuccessful, then a reason field will be returned with more information on why the request failed.

{ "success":  false, "reason": "No node found for ID=n123" }

Update Object

There are two related update methods: PATCH and PUT. When using the PATCH method, the request is assumed to modify only those fields that are sent in the request – any other fields in the object will be left as-is. The PUT method assumes that the entire object should be overwritten by the new data – any fields in the request will be overwritten, and any fields not in the request will be removed or set to default values. Not all object-types allow for PUT operations, and note that a bad PUT call could irreversibly damage the object if some fields are wiped out.

To update the "description" field of a node with PATCH:

curl -X PATCH https://head1.cluster.local/api/v1/node/UID --data \
    '{"description":"this is a new description"}' -H "Authorization: Bearer \
    eyJhbGciOiJIUzI1Ni…"

The return value will simply indicate success or failure:

{"success": true}

In this example, success would indicate that ONLY the "description" field has been modified.

On failure, a "reason" field will give more information on why the request failed:

{"success": false, "reason": "Unhandled parameter(s): ..."}

Delete Object

The DELETE method will permanently remove an object from ClusterWare – there is no way to recover the object’s data once it has been deleted.

To delete an Image from the system:

curl -X DELETE https://head1.cluster.local/api/v1/image/DefaultImage -H \
    "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"

The return value will simply indicate success or failure:

{"success": true}

On failure, a “reason” field will give more information on why the request failed:

{"success": false, "reason": "No image found for ID=DefaultImage"}

Metadata Information

All objects have a metadata endpoint off of their object-class (pluralized) endpoint (for example, /nodes/meta). This endpoint will return more detailed information about the fields available in that object-class.

Note that this is a public endpoint and does not need any authentication token to be accessed.

curl -X GET https://head1.cluster.local/api/v1/nodes/meta

It will return a JSON object that includes a list of fields. Each field in the list will include a path field (the chain of keys to get to that field), summary, source (where the data comes from), and a format (what kind of data it is).

Admin Objects

Admin objects are used to give explicitly specified users access to ClusterWare functionality. Regular HPC users do not need to have Admin objects created for them - this is solely for those who will do administrative or managerial tasks on the cluster.

To create an Admin, the only required data is a name. This must match the username of the user on the underlying operating system. If additional user-data is required, like a full name or department affiliation, it should be stored inside the "description" field.

When issuing requests, the UID field in the URL can be either the actual UID of the object or the name of the object as given in the "name" field. Thus, once a user, user1, has been created, it can be referenced through /admin/user1 or /admin/<UID>.

Data Fields

Admin objects have several fields:

name
      Required: The name of the user on the underlying system description
      Optional: A text string with descriptive information

roles
      Optional: A comma-separated list of ClusterWare roles; while optional, if a user
                does not have any roles assigned, they will not be able to take any
                actions; note that PATCH operations on the “roles” field will
                overwrite the entire field, there is no way to append or extend the
                list of roles

keys
      Optional: A list of one or more ssh keys

gui_settings
      Optional: Used internally by the ClusterWare GUI; it should not be modified
                by end-users

Additional Endpoints

Several endpoints can be used to modify the gui_settings field. Where the standard PATCH actions can update just the gui_settings field, it must update the entire object; these actions allow finer-grained updating of individual keys in that object. Note that this field is used internally by the ClusterWare GUI and admins should not need to modify it directly.

GET /admin/<UID>/gui_settings

PATCH /admin/<UID>/gui_settings

DELETE /admin/<UID>/gui_settings

Several endpoints can be used to update or delete the list of SSH keys that have been stored for the admin.

POST /admin/<UID>/keys

PUT /admin/<UID>/keys

DELETE /admin/<UID>/keys

Similar to the token-refresh process, there is an endpoint that allows an admin to make a new token for use by other tools or automated processes; optional fields can be included in the request:

POST /admin/<UID>/newtoken timeout:  integer; duration for the newly made token

Example

First, create a new admin:

curl -X POST https://head1.cluster.local/api/v1/admins --data '{"name":"admin2"}' \
    -H "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true, "data": "d763705495c3423083ae35f0850da018"}

Get the details on that Admin record:

curl -X GET https://head1.cluster.local/api/v1/admin/d763705495c3423083ae35f0850da018 \
    -H "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true, "data": {"name": "admin2", "roles": ["role.authuser", \
    "role.fulladmin"], "last_modified": 1721850600.3619504, "last_modified_on": \
    "head23.cluster.local", "last_modified_by": "admin1", "uid": \
    "d763705495c3423083ae35f0850da018"}}

Update the record to include a description (switching to “admin2” in the URL):

curl -X PATCH https://head1.cluster.local/api/v1/admin/admin2 --data \
    '{"description":"John Doe, HPC admin"}' -H "Authorization: Bearer \
    eyJhbGciOiJIUzI1Ni…"
{"success": true}

Update the list of roles to be just “role.authuser”:

curl -X PATCH https://head1.cluster.local/api/v1/admin/admin2 --data \
    '{"roles":["role.authuser"]}' -H "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true}

While the PATCH request only updates that one field, leaving other fields as-is, the update to that field will overwrite the old data. There is no way to append or add to the list of roles.

Verify the new data:

curl -X GET https://head1.cluster.local/api/v1/admin/admin2 -H \
    "Authorization: Bearer eyJhbGciOiJIUzI1Ni…”
{"success": true, "data": {"name": "admin2", "roles": ["role.authuser"], \
    "last_modified": 1721851033.3245502, "last_modified_on": "head23.cluster.local", \
    "last_modified_by": "admin1", "description": "John Doe, HPC admin", "uid": \
    "d763705495c3423083ae35f0850da018"}}

Finally, delete the account:

curl -X DELETE https://head1.cluster.local/api/v1/admin/admin2 -H \
    "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true}

Node Objects

Node objects represent the computational nodes and other controllable entities inside the cluster (switches, PDUs, etc.).

When issuing requests, the UID field in the URL can be either the actual UID of the object, the name of the object as given in the "name" field, the MAC address, or the IP address. Thus, once a user, user1, has been created, it can be referenced through /admin/user1 or /admin/<UID>.

Data Fields

Node objects can have several fields:

name
      Assigned by ClusterWare; the name is computed from the naming pool pattern and
      the node’s index (which is also computed based on that pool’s membership)

description
      Optional: A text string with descriptive information

type
      Optional: Defaults to ‘compute’, can be one of ('unknown','compute','head',
                'simulated')

mac
      Required: Every node must have a MAC address

attributes
      Optional: A set of key-value pairs that are assigned to the node and may be used
                when configuring the node at boot-time

groups
      Optional: An ordered list of Attribute Groups that this node belongs to;
                attributes from each group will be applied (overwritten) based on the
                order of the groups

naming_pool
      Optional: A naming pool may be assigned and used to calculate the
                name, index, and IP address of the node

index
      Assigned by ClusterWare; the index (integer) is computed by ClusterWare based on
      the naming pool

ip
      Assigned by ClusterWare; the IP address is computed by ClusterWare based on the
      naming pool

power_uri
      Optional: The URI of the node’s BMC or IPMI controller; the power_uri can be a
                template with bracketed fields that are substituted with the node’s
                attribute, status, or hardware values (see examples below)

redfish_uri
      Optional

Additional Endpoints

Several endpoints provide finer-grained access to the list of Attribute Groups that the node belongs to. For example, POST /node/<UID>/groups allows appending one or more groups to the current list. To completely replace the list of groups, use the PATCH /node/<UID> action with the groups key.

GET /node/<UID>/groups
     Returns a list of Attribute Groups (UIDs) that the node belongs to

POST /node/<UID>/groups
     Accepts one key or a list of keys representing Attribute Groups that will be
     appended to the current list


DELETE /node/<UID>/groups
     Accepts one key or a list of keys representing Attribute Groups that will be
     removed from the current list of Attribute Groups

Several endpoints provide finer-grained access to the list of attributes assigned to this specific node. Issuing a POST /node/<UID>/attributes action will append one or more groups to the current list. To completely replace the attributes, use the PATCH /node/<UID> action with the attributes key. Note that nodes will inherit attributes from all groups that they belong to, and will then overwrite them with any node-specific attributes.

GET /node/<UID>/attributes
     Returns a JSON object for all of the attributes (key-value pairs) for this node;
     these may have assigned specifically to this node or may have been inherited from
     any of the Attribute Groups that it belongs to

PUT /node/<UID>/attributes
     Replaces the current set of node-specific attributes with the sent data; note
     that if a key is removed from the current set, it may still be inherited from a
     joined Attribute Group

PATCH /node/<UID>/attributes
     Updates the current set of node-specific attributes with the sent data; these
     values will take precedence over any joined Attribute Groups

DELETE /node/<UID>/attributes
     Accepts one key or a list of keys to be removed from the node-specific attributes;
     note that if an attribute is set by an Attribute Group, it will still be present
     in the node’s overall list of attributes (until it is removed from that Attribute
     Group or the node leaves that group)

Several endpoints are designed for power control functionality. The power_uri field is needed for deeper power control functions. For example, a power-off action will attempt to execute a graceful shutdown, but if that fails it will fallback to an IPMI or BMC power-off.

GET /node/<UID>/power_uri
     Returns a JSON object with “parsed” and “unparsed” keys; the “unparsed” key
     contains a single URI that can be used to connect to the power control unit; the
     “parsed” key contains an object with fields representing the server, path, etc.
     that have been parsed from the URI

GET /node/<UID>/power_state
     Returns the power state of the node:  on, off, unknown

PUT /node/<UID>/power_state
     Accepts an object with “state” and “force” fields (all optional); “state” is one
     of: power on, power off; “force” is True or False.  There is an advanced option,
     “steps”, which allows for more control over the sequence of power-control attempts
     (for example, hard versus soft power-off) – contact Penguin Solutions for more
     information.

Several endpoints are used for the node status and hardware reporting system. Note that this is separate from the ClusterWare Monitoring and Alerting system; this data is kept inside the ClusterWare database and can be used in various templates and node-selectors. The specific values to be found in status and hardware can be configured using a plugin system. More information on monitoring and the plugin system can be found in the ClusterWare Admin and Reference Guides.

GET /node/<UID>/status
     Returns a JSON object with the node’s status information – this can be a sizeable
     set of data (several KB); with default plugins, status will include things like
     load average (load_avg) and memory usage (ram_free) as well as a list of the
     loaded packages and modules and many more.

POST /node/putstatus
     Accepts a JSON object with a “uid” field (required) and “status” and/or “hardware”
     keys; the “status” or “hardware” keys are JSON objects containing the actual data.
     This endpoint is intended to be used by ClusterWare tools to update node status
     information.

POST /node/putattribs
     Accepts a JSON object with a “uid” field (required) and a set of key-value pairs;
     the key-value pairs will be added to the node’s current attributes. This endpoint
     is intended to be used by ClusterWare tools to update node attribute information.

Related to the above, the following two endpoints are used by the compute nodes to update information on the ClusterWare head nodes. These endpoints do not use token-based authentication, but instead look at the IP-address of the incoming connection to determine which node is being updated.

Caution

Improper use of these endpoints could corrupt the ClusterWare node information, which could lead to improper functioning of Dynamic Groups, node selectors, and the Publish-Subscribe system. Contact Penguin Solutions for more information.

PUT /node/putstatus
     Accepts a JSON object with “status” and/or “hardware” keys, each of which is a
     JSON object containing the actual data; unlike the POST version of this endpoint,
     there is no “uid” key needed with the PUT operation

PUT /node/putattribs
     Accepts a JSON object with key-value pairs; these key-value pairs will be added
     to the node’s attributes; unlike the POST version of this endpoint, there is no
     “uid” key needed with the PUT operation

To interact with the nodes, including running commands on them, several endpoints can be used:

PUT /node/<UID>/exec
     Accepts a JSON object with “cmd” (required) and an optional “stdin” key; if
     “stdin” is sent, it will be used as the standard input for an interactive command;
     the output will be an octet-stream with the output from the command.  Note that
     this output format is different from other ClusterWare commands – there are no
     “success” or “data” keys, just the raw data from the command.

Example

Create a new node:

curl -X POST https://head1.cluster.local/api/v1/nodes --data \
    '{"mac":"11:22:33:44:55:66"}' -H "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true, "data": "341b9947f6e644b78f6d88f5d7f898f4"}

Verify the node’s data using the returned UID:

curl -X GET https://head1.cluster.local/api/v1/node/341b9947f6e644b78f6d88f5d7f898f4 \
    -H "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true, "data": {"mac": "11:22:33:44:55:66", "attributes": \
    {"_boot_config": "DefaultBoot"}, "index": 3, "ip": "192.168.122.103", \
    "type": "compute", "last_modified": 1721997178.5100713, "last_modified_on": \
    "head23.cluster.local", "last_modified_by": "admin1",  "uid": \
    "341b9947f6e644b78f6d88f5d7f898f4", "groups": [], "hardware": {}, \
    "power_uri": null, "name": "n3", "hostname": "n3", "domain": "cluster.local"}}

Since Nodes can be referenced by name or MAC address, the same information can be found using:

curl -X GET https://head1.cluster.local/api/v1/node/11:22:33:44:55:66 -H \
    "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"

And now that the node name is known, the same information can be found with:

curl -X GET https://head1.cluster.local/api/v1/node/n3 -H "Authorization: Bearer \
    eyJhbGciOiJIUzI1Ni…"

Set attributes on the node itself (not through an Attribute Group):

curl -X PATCH https://head1.cluster.local/api/v1/node/n3/attributes --data \
    '{"ipmi_user":"service", "ipmi_pass":"servicepass"}' -H "Authorization: \
   Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true}

Verify the new data, grabbing just the attributes (not the whole node record):

curl -X GET https://head1.cluster.local/api/v1/node/n3/attributes -H \
    "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true, "data": {"_boot_config": "DefaultBoot","ipmi_user": "service", \
    "ipmi_pass": "servicepass"}}

Setting the power_uri using the attributes in the template

curl -X PATCH https://head1.cluster.local/api/v1/node/n3 --data \
    '{"power_uri":"ipmi://<ipmi_user>:<ipmi_pass>@10.10.1.3/ipmi"}' \
    -H "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true}

Verify the power_uri and its substitutions

curl -X GET https://head1.cluster.local/api/v1/node/n3/power_uri -H \
    "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true, "data": {"unparsed": "ipmi://service:servicepass@10.10.1.3/ipmi", \
    "parsed": {"scheme": "ipmi", "schemes": "", "server": "10.10.1.3", "path": \
    "ipmi", "server_username": "service:servicepass", "username": null, \
    "password": null, "host": "ipmi"}}}

Notice that the text strings “<ipmi_user>” and “<ipmi_password>” have been substituted for the values from the node’s attributes. To get the un-substituted value for the power_uri, simply use the GET /node/<UID> endpoint.

To determine the power state of the node:

curl -X GET https://head1.cluster.local/api/v1/node/n3/power_state -H \
    "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true, "data": "on"}

Note that if the node is unreachable via its primary or management network, it may take a while for the system to determine that the node is down just due to standard network timeouts.

To power off the node:

curl -X PUT https://head1.cluster.local/api/v1/node/n3/power_state --data \
    '{"state":"power off"}' -H "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true}

Attribute-Group Objects

An Attribute Group object represents a set of attributes that will be attached to a node based on its membership in the group. A node can be a member of several groups, arranged in a hierarchical list. For example, a node that is a member of group1 and group2 will inherit group1’s attributes, which may then be overwritten by group2’s attributes.

When issuing requests, the UID field in the URL can be either the actual UID of the object or the name of the object as given in the “name” field.

Data Fields

The Attribute Group fields are:

name
     Required: The name for the group

description
     Optional: A text string with descriptive information

attributes
     Optional: A JSON-object containing key-value pairs of attributes

While the attributes field accepts a generic JSON object, it can only reference one level into that key-value store.

Additional Endpoints

Several endpoints can be used to directly manipulate the attribute key-value store instead of going through the Attribute object first. The PATCH /attribs/<UID> command allows for overwriting the entire attributes field, but cannot be used to add or append attributes one at a time. The PATCH /attribs/<UID>/attributes endpoint allows for that kind of direct update.

GET /attrib/<UID>/attributes
     Returns a JSON object containing the key-value pairs

PUT /attrib/<UID>/attributes
     Replaces the current set of key-value pairs with the sent data; any keys not in
     the sent data will be removed from the Attribute Group

PATCH /attrib/<UID>/attributes
     Updates the current set of key-value pairs with the sent data; only the keys that
     are sent will be modified in the Attribute Group’s data; any other keys will be
     left as-is

DELETE /attrib/<UID>/attributes
     Accepts one key or a list of keys to be removed from the Attribute Group’s data;
     note that a node can still show that attribute key as present if a node-specific
     attribute has been set, or if the node is joined to another Attribute Group where
     it is set

Example

Create a new Attribute Group:

curl -X POST https://head1.cluster.local/api/v1/attribs --data '{"name":"MyAttribs"}' \
    -H "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true, "data": "5997e993e0bb49568bef18536614b733"}

Read the basic information:

curl -X GET https://head1.cluster.local/api/v1/attrib/MyAttribs -H \
    "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true, "data": {"name": "MyAttribs", "last_modified": 1721852251.1698143, \
    "last_modified_on": "head23.cluster.local", "last_modified_by": "admin1", \
    "uid": "5997e993e0bb49568bef18536614b733", "attributes": {}}}

Update the attributes key-value store through the main record:

curl -X PATCH https://head1.cluster.local/api/v1/attrib/MyAttribs --data \
    '{"attributes":{"foo":"bar"}}' -H "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true}

Verify that the update worked:

curl -X GET https://head1.cluster.local/api/v1/attrib/MyAttribs -H \
    "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true, "data": {"name": "MyAttribs", "last_modified": 1721852433.4113355, \
    "last_modified_on": "head23.cluster.local", "last_modified_by": "admin1", \
    "attributes": {"foo": "bar"}, "uid": "5997e993e0bb49568bef18536614b733"}}

To get just the attributes and not the whole record:

curl -X GET https://head1.cluster.local/api/v1/attrib/MyAttribs/attributes -H \
    "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true, "data": {"foo": "bar"}}

Directly manipulate the attributes key-value store to add new data:

curl -X PATCH https://head1.cluster.local/api/v1/attrib/MyAttribs/attributes --data \
    '{"abc":"def"}' -H "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true}

Verify the new data:

curl -X GET https://head1.cluster.local/api/v1/attrib/MyAttribs/attributes -H \
    "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true, "data": {"foo": "bar", "abc": "def", "last_modified": \
    1721852648.6145608, "last_modified_on": "533a8c21fd5642c38138214d7ad783ae", \
    "last_modified_by": "admin1"}}

Directly delete one key out of the key-value store (send a list of keys to delete):

curl -X DELETE https://head1.cluster.local/api/v1/attrib/MyAttribs/attributes --data \
    '["abc"]' -H "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true}

And verify that the key is gone:

curl -X GET https://head1.cluster.local/api/v1/attrib/MyAttribs/attributes -H \
    "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true, "data": {"foo": "bar", "last_modified": 1721852648.6145608, \
    last_modified_on": "533a8c21fd5642c38138214d7ad783ae", "last_modified_by": \
    "admin1"}}

To delete the object entirely:

curl -X DELETE https://head1.cluster.local/api/v1/attrib/MyAttribs -H \
    "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true}

Boot Config Objects

A Boot Config object represents a set of information used to boot up a node from power-on to a running OS image on the node. It may include specific command-line parameters for the booting node, a “boot style” (for example, ram-based image or disked image), kickstart files, etc.

When issuing requests, the UID field in the URL can be either the actual UID of the object or the name of the object as given in the “name” field.

Data Fields

The Attribute Group fields are:

name
     Required: The name for the Boot Config

kernel
     Required: This is the kernel (file) being used by the Boot Config; note that since
     this requires a large file to be uploaded, the standard POST/PATCH endpoints will
     not work to update the kernel - additional endpoints are provided for handling
     these files

initramfs
     Required: This is the initramfs (file) being used during the early boot phases;
     note that since this requires a large file to be uploaded, the standard POST/PATCH
     endpoints will not work to update the initramfs - additional endpoints are provided
     for handling these filesdescription

     Optional: A text string with descriptive information

frozen
     Optional: A True/False indicator that allows admins to block changes to the boot
               config; note that is intended as a protection against accidents, not
               against malicious attacks, since one can simply set frozen=False and
               then make changes.

cmdline
     Optional: Command-line to be used when booting the operating system; this may
               include options for SELinux enforcement or power-control

image
     Optional: A UID or name for a ClusterWare Image object (see below); note that
               ClusterWare stores this as a UID, but will accept a UID or name when
               creating or updating the Boot Config

boot_style
     Optional: A string representation of the type of boot-up process being used, one
               of: ('rwram','roram','iscsi','next','disked','sanboot','live'); the
               default is “rwram” and indicates a node that will be booted into a
               ram-based image that readable and writable

repo
     Optional

kickstart
     Optional: Indicates the kickstart file to be used for disk-based installations
               that are using Kickstart; this should be a file that has been copied
               or created in the /opt/scyld/clusterware/kickstarts directory.

Additional Endpoints

Additional object-class endpoints are available:

GET /bootconfigs/errors
     Will check all Boot Config entries that they have valid data, that any referenced
     images or files are present, etc.; returns a JSON object with a “success” field;
     if an error occurs, a “reason” field will give more information on why it failed

GET /bootconfigs/mkiso
     Accepts a JSON object with “uid” and “image” keys, and will create and download a
     bootable ISO image. This is an advanced feature, please contact Penguin Solutions
     for more information.

As mentioned earlier, the kernel and initramfs may be large files and thus must be uploaded separately – they cannot be “updated” with the standard POST/PATCH actions. To interact with these files, use the following endpoints:

GET /bootconfig/<UID>/kernel
     Returns a file containing the kernel being used by this Boot Config. Note that
     the output format is different from other ClusterWare commands – there are no
     “success” or “data” keys, just the binary data of the file being requested.

PUT /bootconfig/<UID>/kernel
     Replaces the current kernel file with the uploaded file

DELETE /bootconfig/<UID>/kernel
     Deletes the kernel file associated with this Boot Config; in multi-head
     configurations, the file will be deleted from all heads automatically

GET /bootconfig/<UID>/initramfs
     Returns a file containing the initramfs being used by this Boot Config. Note that
     the output format is different from other ClusterWare commands – there are no
     “success” or “data” keys, just the binary data of the file being requested

PUT /bootconfig/<UID>/initramfs
     Replaces the current initramfs file with the uploaded file

DELETE /bootconfig/<UID>/initramfs
     Deletes the initramfs file associated with this Boot Config; in multi-head
     configurations, the file will be deleted from all head nodes automatically

For kickstart-based deployments, the kickstart file can be a template that uses “<variable>” syntax to substitute values from the node. To retrieve the parsed and substituted kickstart file, use the following endpoint. Unlike kernel and initramfs files, kickstart files are NOT automatically synchronized across head nodes – admins must manually copy the file from one head node to the others.

GET /bootconfig/<UID>/kickstart
     Returns the parsed and substituted kickstart file; the output format is
     different from other ClusterWare commands – there are no “success” or “data”
     keys, just the (text) data of the file being requested.

Since Boot Configs are critical to the operation of the cluster, an endpoint can be used to check that the required data is available and valid. For example, to check that the image file being used is actually present:

GET /bootconfig/<UID>/errors
     Checks that entries in the boot config are valid and return a JSON object
     with a “success” field; if an error occurs, a “reason” field will give more
     information on why it failed

An endpoint is provided to export a Boot Config for backup or sharing:

GET /bootconfig/<UID>/export
     This is an advanced feature, please contact Penguin Solutions for more
     information

Example

Create a new Boot Config, using an existing DefaultImage as the base image:

curl -X POST https://head1.cluster.local/api/v1/bootconfigs --data \
    '{"name":"NewBoot","image":"DefaultImage"}' -H \
    "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true, "data": "ed31013d670745139681c46cf657ed40"}

Note that the image can be referenced by UID or, as shown here, by name. Verify the data:

curl -X GET https://head1.cluster.local/api/v1/bootconfig/NewBoot -H \
    "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true, "data": {"name": "NewBoot", "image": "DefaultImage", \
    "last_modified": \1721921837.5399132, "last_modified_on": "head23.cluster.local", \
    "last_modified_by": "admin1", "uid": "ed31013d670745139681c46cf657ed40"}}

Set it to be "frozen" so that future changes cannot be made:

curl -X PATCH https://head1.cluster.local/api/v1/bootconfig/NewBoot --data \
    '{"frozen":true}' -H "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true}

Now that it is frozen, attempt to modify the "description" field:

curl -X PATCH https://head1.cluster.local/api/v1/bootconfig/NewBoot --data
    '{"description":"new description"}' -H "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": false, "reason": "Cannot modify frozen boot configuration."}

This Boot Config does not yet have a kernel or initramfs and thus would not be able to actually boot any nodes yet. Using the existing DefaultBoot (created during installation), download its kernel and initramfs:

curl -X GET https://head1.cluster.local/api/v1/bootconfig/DefaultBoot/kernel -o \
    defaultboot_kernel -H "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"

curl -X GET https://head1.cluster.local/api/v1/bootconfig/DefaultBoot/initramfs -o \
    defaultboot_initramfs -H "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"

Image Objects

An Image object represents a file system that will be deployed onto a compute node. It is not intended to have absolutely all software that an end-user might want, but rather, a somewhat minimal set of drivers, configuration files, tools, and middleware to bring up the node. Network-mounted file systems may be used to provide additional software and libraries for end-users.

When issuing requests, the UID field in the URL can be either the actual UID of the object or the name of the object as given in the "name" field.

Data Fields

The Attribute Group fields are:

name
     Required: The name for the image

content
     Required: This is the content of the file system that will be used in this Image;
               since this requires a large file to be uploaded, the standard
               POST/PATCH endpoints will not work to update the content - additional
               endpoints are provided for handling it below

description
     Optional: A text string with descriptive information

frozen
     Optional: A True/False indicator that allows admins to block changes to the boot
               config; this is intended as a protection against accidents, not
               against malicious attacks, since one can simply set frozen=False and
               then make changes.

parent
     Optional: A UID or name of a “parent” Image object that the current object was
               derived from; this field is for informational purposes only and is not
               used during any actions (for example, changes to a parent Image are not
               propagated into its children); ClusterWare stores this as a
               UID, but will accept a UID or name when creating or updating the Image

distro
     Optional: A UID of a distro (a Software Distribution object)

Additional Endpoints

As mentioned earlier, the content of an Image is a large file and thus must be uploaded separately – it cannot be “updated” with the standard POST/PATCH actions. To interact with the content file, use the following endpoints:

GET /image/<UID>/content
     Returns a file containing the file system image being used by this Image object.
     The output format is different from other ClusterWare commands – there
     are no “success” or “data” keys, just the binary data of the file being requested

PUT /image/<UID>/content
     Replaces the current content file with the uploaded file

DELETE /image/<UID>/content
     Deletes the content file associated with this Image; in multi-head configurations,
     the file will be deleted from all heads automatically

GET /image/<UID>/content/stat
     Returns a JSON object containing statistics on the image: the file’s size (“size”)
     and last modification time (“mtime”)

GET /image/<UID>/content/info
     Returns a JSON object containing more detailed statistics on the image: the file’s
     size (“size”), last modification time (“mtime”), checksum ("chksum"), a reference
     count (“refcnt”), and the file format (“fmt”, currently “cwsquash”)

There is one additional endpoint that is used when capturing an image from a running compute node. This is an advanced feature; please contact Penguin Solutions for more information.

GET /image/{uid}/capture
     Accepts a JSON object with “uid” key (required), and one or more optional keys:
     “exclude”, “credentials”, “compress”.

Example

Create an empty image:

curl -X POST https://head1.cluster.local/api/v1/images --data '{"name":"NewImage"}' \
    -H "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true, "data": "d16d9eb8786c408ba32780ee6b722a50"}

Look at an existing Image (DefaultImage will be created at installation):

curl -X GET https://head1.cluster.local/api/v1/image/DefaultImage -H \
    "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true, "data": {"name": "DefaultImage", "distro": "CentOS", "parent": null, \
    "description": "Default image generated by scyld-add-boot-config", "exports": \
    {"head23.cluster.local": {"targetcli": {"category": "iscsi", "location": \
    "iqn.1998-04.com.penguincomputing:cb2eeba6fe3748febbb15c7cc1cfb165"}, \
    "last_modified": 1721928167.775344, "last_modified_on": "head23.cluster.local"}}, \
    "content": {"cwsquash": {"size": 1222410240, "mtime": 1721919588.6732733, \
    "chksum": "sha1:7e24ac56d109394755302377c9226fa111aae45d", "filename": \
    "486c1857bd214d3fad56dea1399b6440", "uid": "486c1857bd214d3fad56dea1399b6440"}, \
    "last_modified": 1721919589.1442792, "last_modified_on": "head23.cluster.local", \
    "last_modified_by": "admin1"}, "last_modified": 1721919581.66072, \
    "last_modified_on": "head23.cluster.local", "last_modified_by": "admin1", \
    "uid": "cb2eeba6fe3748febbb15c7cc1cfb165"}}

Look into the details statistics for the image:

curl -X GET https://head1.cluster.local/api/v1/image/DefaultImage/content/info \
    -H "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true, "data": {"size": 1222410240, "mtime": 1721919588.6732733, "chksum": \
    "sha1:7e24ac56d109394755302377c9226fa111aae45d", "refcnt": 1, "fmt": "cwsquash"}}

Dynamic Group Objects

Where Attribute Groups require intentional effort to join or leave, Dynamic Groups (DynGroups) are a way to group nodes based on shared or common attributes, status, or hardware information. DynGroups also do not alter a node’s attributes, so they are most useful in targeting an action at a group of similar nodes.

When issuing requests, the UID field in the URL can be either the actual UID of the object or the name of the object as given in the "name" field.

Data Fields

The DynGroups fields are:

name
     Required: The name for the Dynamic Group

selector
     Required: A string representing a node-selector function (see below)

description
     Optional: A text string with descriptive information

A node-selector function is a logical function that is computed based on a given node’s information. Since a node’s boot configuration is set in the _boot_config attribute, the following will select all nodes that using DefaultBoot:

a[_boot_config]=="DefaultBoot"

the a[..] means to look up a nodes attribute, similarly h[..] can be used for hardware and s[..] for status. The amount of total memory on a node is given in the hardware information, under the ram_total key:

h[ram_total] > 100000

will give the set of nodes with more than 1000000 bytes of memory.

More information on the node-selector language can be found in the ClusterWare Admin and Reference Guides.

Additional Endpoints

To find the set of nodes that are currently in a given DynGroup, use the following endpoint:

GET /dyngroup/<UID>/nodes
     Returns a JSON object with a list of node UIDs; if no nodes are currently in the
     dynamic group, an empty list will be returned

Example

Create a dynamic group:

curl -X POST https://head1.cluster.local/api/v1/dyngroups --data \
    '{"name":"BigMemory","selector":"h[ram_total] > 100GB"}'
    -H "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true, "data": "b30886d9c8ca40d99d66b668074811b1"}

Verify the group’s information:

curl -X GET https://head1.cluster.local/api/v1/dyngroup/BigMemory -H \
    "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true, "data": {"name": "BigMemory", "selector": "h[ram_total] > 100GB", \
    "parsed": "(hardware[\"ram_total\"] > 100GB)", "last_modified": 1721930148.843629, \
    "last_modified_on": "head23.cluster.local", "last_modified_by": "admin1", \
    "uid": "b30886d9c8ca40d99d66b668074811b1"}}

Get the list of nodes currently in this DynGroup:

curl -X GET https://head1.cluster.local/api/v1/dyngroup/BigMemory/nodes -H \
    "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true, "data": ["199eadbea2084b80a4efcf445538efc5", \
    "d3b59618750e4957bc3139a0a29cb1a8", "4343fc9a431d49e89639b8cf3644db9a", \
    "9e831349cbcf484f8db075e12ef4dd9d", "35d6faece6a7411cb26a7c7b02fda708"]}

Delete the DynGroup:

curl -X DELETE https://head1.cluster.local/api/v1/dyngroup/BigMemory -H \
    "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true}

Naming Pool Objects

Naming Pools provide a mechanism to tie groups of nodes together through a common naming scheme, like n001 through n100. There is a default naming scheme that nodes will be assigned into; alternatively, when creating a node, it can be directly inserted into an existing Naming Pool.

In addition to naming the nodes according to a pattern, the Naming Pool can also provide offsets to IP addresses or include nodes into specified network segments.

When issuing requests, the UID field in the URL can be either the actual UID of the object or the name of the object as given in the "name" field.

Data Fields

The Naming Pool fields are:

name
     Required: The name for the Dynamic Group

pattern
     Required: A string representing a naming pattern; a pattern may have one or more
               letters followed by a set of curly-braces followed by another one or
               more letters (see below)

description
     Optional: A text string with descriptive information

first_index
     Optional: Sets the first index for nodes added to this pool; default is 0

ip_base
     Optional: Sets a base IP address for the first node in the pool; default is empty
               (use the next available address in the default network)

ip_offset
     Optional: Sets an offset for the IP address of the first node in the pool; default
               is empty (use the next available address in the default network)

network
     Optional: Sets the Network to use when setting IP addresses

group
     Optional: Sets an Attribute Group object that all nodes in this pool will inherit
               from; any node added to the pool will automatically be assigned the
               attributes of this group (unless other Attribute Groups are assigned)

parent
     Optional: Sets a parent Naming Pool for nested pools

     There are several options for how naming pool patterns may be constructed:

pattern=”n{}”
     This is the default, and indicates that nodes will be named “n0” and up; note
     that in such a pattern, the name length is not constant which may lead to output
     formatting errors (i.e. “n0” versus “n100” will lead to a 2 character offset)

pattern=”gpu{:03d}”
     Will give names like gpu000, gpu001, gpu002, etc.; the “:03d” is formatted,
     zero-padded, 3 digits

Additional Endpoints

Several additional endpoints are available:

GET /namingpools/info/<NODE>
     For a given node, NODE, the system will reply with the naming pool information
     used when naming that node

PUT /namingpool/<UID>/push
     Used to push node names to be updated; this is an advanced feature, please contact
     Penguin Solutions for more information.

Example

Create a naming pool:

curl -X POST https://head1.cluster.local/api/v1/namingpools --data \
    '{"name":"gpu","pattern":"gpu{}"}' -H "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true, "data": "1049f3b2f2d744f088a4ee6cc3ecfc91"}

Check on a node’s naming pool:

curl -X GET https://head1.cluster.local/api/v1/namingpools/info/gpu0 \
    -H "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true, "data": {"index": 0, "pattern": "gpu{}"}}

Software Repository Objects

Software Repository objects (repos) are used to collect information about an upstream or local repository for software packages.

When issuing requests, the UID field in the URL can be either the actual UID of the object or the name of the object as given in the "name" field.

Data Fields

Admin objects have several fields:

name
     Required: The name of the user on the underlying system

description
     Optional: A text string with descriptive information

full_name
     Optional: A text string for identifying the repos

urls
     Optional: A list of URLs for the repos

mirrors
     Optional: A list of mirror URLs for the repos

disable
     Optional: A list of True/False flags for the URLs

keys
     Optional: A list of keys for the URLs

check
     Optional

rhel_entitlement
     Optional: RedHat license entitlement key

Additional Endpoints

For locally hosted repos, several endpoints can be used to investigate the ISO:

GET /repo/<UID>/iso
     Downloads the ISO image for this repo.  Note that the output format is different
     from other ClusterWare commands – there are no “success” or “data” keys, just the
     binary data of the ISO file being requested

PUT /repo/<UID>/iso
     Uploads an ISO for this repo

DELETE /repo/<UID>/iso
     Deletes the ISO for this repo; note that the repo's object itself will remain,
     just the ISO will be deleted

GET /repo/<UID>/iso/stat
     Returns basic statistics about the ISO file

Software Distribution Objects

Software Distribution objects (distros) are used to collect information about a software distribution. For example, which repos hold packages and what packaging scheme is used.

When issuing requests, the UID field in the URL can be either the actual UID of the object or the name of the object as given in the "name" field.

Data Fields

Admin objects have several fields:

name
     Required: the name of the user on the underlying system

description
     Optional: A text string with descriptive information

repos
     Optional: A list of one or more Software Repository objects

packaging
     Optional: A string representing the packaging scheme:  rpm, deb, apk; if it cannot
               be inferred from other data, “rpm” will be assumed

release
     Optional: A string representing the name of the release

Additional Endpoints

There are no additional endpoints for distros; the basic operations all function as expected. For example, GET /distro/<UID> will return information about the distro.

Network Objects

Network objects are used to collect information about network subnets that can be used for deploying compute nodes.

When issuing requests, the UID field in the URL can be either the actual UID of the object or the name of the object as given in the "name" field. For Networks the name field is optional, so using the UID may be the most reliable approach.

Data Fields

Network objects have several fields:

first_ip
     Required: The starting IP address for this network

ip_count
     Required: (Integer) number of IP addresses that may be assigned on this subnet

mask_bits
     Required: (Integer) number of bits for the network mask

name
     Optional: The name of the user on the underlying system

description
     Optional: A text string with descriptive information

first_index
     Optional: (Integer) number for the first index of the nodes in this network

router_ip
     Optional: The IP address for the router on this network

gateway_ip
     Optional: The IP address for the gateway on this network

domain
     Optional: The domain name to be set for this network

node_iface
     Optional: Network interface used during booting

Additional Endpoints

There are several additional endpoints for networks:

GET /nets/byiface/<PART>
This endpoint is deprecated and will be removed in a future release; returns a
     JSON object with a list of networks that reference the interface name, NAME;
     full or partial matches are returned

GET /nets/byname/<NAME>
     Returns a JSON object with a list of networks that reference the network name, NAME;
     full or partial matches are returned

GET /nets/byip/<IPADDR>
     Returns a JSON object with a list of networks that reference the partial or full
     IP address, IPADDR

GET /nets/bykey/<PART>
     Returns a JSON object with a list of networks that reference the partial or full
     UID, PART

Git Repository Objects

Git Repository objects (gitrepos) are used to create and manage locally hosted Git repositories, which may be useful for automated configuration systems.

When issuing requests, the UID field in the URL can be either the actual UID of the object or the name of the object as given in the "name" field.

Data Fields

Admin objects have several fields:

name
     Required: The name of the user on the underlying system

description
     Optional: A text string with descriptive information

public
     Optional

url
     Optional: A URL for the git repos that will be used for synchronization; note that
               either “url” or “upstream” can be defined, but not both

upstream
     Optional: A URL for an upstream git repos that will be used for synchronization;
               note that either “url” or “upstream” can be defined, but not both

branch_map
     Optional: A list of local-to-remote branch mappings

sync_period
     Optional: Time between synchronization events for this gitrepos; can be a number
               (seconds) or a string of the form “10m”, “2h”, “1d” for minutes, hours,
               or days, respectively

Additional Endpoints

For gitrepos, several endpoints are available:

GET /gitrepo/{uid}/url
     Returns a URL string that can be used to clone the gitrepo. The output
     format is different from other ClusterWare commands – there are no “success” or
     “data” keys, just the URL string. This endpoint is public and does not require an
     authentication token

GET /gitrepo/{uid}/repo
     Returns the top-level file in the repo.  The output format is different
     from other ClusterWare commands – there are no “success” or “data” keys, just the
     (text) file. This endpoint is public and does not require an authentication token

GET /gitrepo/{uid}/repo/<PATH>
     Returns the file in the repo at location PATH.  The output format is
     different from other ClusterWare commands – there are no “success” or “data” keys,
     just the (text) file. This endpoint is public and does not require an
     authentication token

GET /gitrepo/{uid}/content
     Returns the top-level file in the repo.  The output format is different
     from other ClusterWare commands – there are no “success” or “data” keys, just the
     (text) file. This endpoint is public and does not require an authentication token

GET /gitrepo/{uid}/content/<PATH>
     Returns the file in the repo at location PATH.  The output format is
     different from other ClusterWare commands – there are no “success” or “data” keys,
     just the (text) file. This endpoint is public and does not require an
     authentication token

GET /gitrepo/{uid}/sync
     While this is a GET operation, it accepts a JSON object payload with an “action”
     key (required) and “branchmap” key (optional); action should be one of: 'status',
     'checkout', 'reset', 'pull', 'rebase'

POST /gitrepo/{uid}/sync
     Accepts a JSON object with an “action” key (required) and a “branchmap” key
     (optional); action should be one of: 'status', 'checkout', 'reset', 'pull',
     'rebase'

GET /gitrepo/{uid}/branches
     While this is a GET operation, it accepts a JSON object with optional keys:
     branchmap, all, filter; the branchmap is a list of branches to get information
     about, the all parameter is True/False, and filter allows for more arbitrary
     filtering of the gitrepos list

DELETE /gitrepo/{uid}/branches
     Accepts a JSON object with one or more optional keys:  “branches” (a list of
     branches to delete) or “all” (True/False, delete all branches in the gitrepos)

Hostname Objects

ClusterWare runs an DNS service to handle the name records needed for compute nodes and that service can be extended to provide other hostname records as well. If a hostname record includes a MAC address, then lusterWare will include it in its DHCP service.

When issuing requests, the UID field in the URL can be either the actual UID of the object or the name of the object as given in the "name" field.

Data Fields

name
     Required: the name for the host

type
     Required: a string representing the type of DNS record this will be: arec (IPv4),
     aaaarec (IPv6), or srvrec (service)

description
     Optional: a text string with descriptive information

ip
     Required for arec and aaaarec: the IP address associated with this name

mac
     Optional for arec and aaaarec: the MAC address associated with this name; if no
     mac is given, then DHCP will not be configured for this host

target
     Required for srvrec: the target server that is running this service

port
     Required for srvrec: the port that the service is running on

service
     Optional for srvrec: the service name for this SRV record, defaults to the name
     of the record

proto
     Optional for srvrec: the protocol that the service uses:  tcp or udp

weight
     Optional for srvrec: the “weight” given to this SRV record; if multiple SRV records
     exist for the same target, the higher weight will be preferred

priority
     Optional for srvrec: the “priority” given to this SRV record; if multiple SRV
     records exist for the same target, the higher priority will be preferred

domain
     Optional for srvrec: the domain portion of the FQDN; if not specified, it will
     default to whatever the ClusterWare head node is configured with

Additional Endpoints

An additional endpoint is provided to search the hostnames by UID:

GET /hostnames/bypart/<PART>
     A partial UID can be sent in <PART> and the system will return a list of all
     hostname UIDs that match that partial UID

Example

Create a hostname record:

curl -X POST https://head1.cluster.local/api/v1/hostnames --data \
    '{"name":"nfsserver","ip":"10.1.1.10"}' \
    -H "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true, "data": "e921725181c741fba6f4ec8a027a432f"}

Verify the record’s contents:

curl -X GET https://head1.cluster.local/api/v1/hostname/nfsserver -H \
    "Authorization: Bearer eyJhbGciOiJIUzI1Ni…"
{"success": true, "data": {"type": "arec", "name": "nfsserver", "ip": "10.1.1.10", \
    "last_modified": 1721931565.353962, "last_modified_on": "head23.cluster.local", \
   "last_modified_by": "admin1", "uid": "e921725181c741fba6f4ec8a027a432f"}}

Cluster-wide Endpoints

There are a number of endpoints dedicated to cluster-wide information, or ClusterWare configuration information:

GET /cluster
     Returns a JSON object with detailed information about the cluster, including the
     current time on the cluster, the monitoring and authentication configuration,
     image formats, plugins, etc.

PATCH /cluster
     Accepts a JSON object with one or more key-value pairs; for each key, the
     corresponding entry in the cluster database is overwritten; keys may be:
       - default_group (change the default group that nodes are assigned to)
       - naming (change the default naming scheme)
       - accept_new_nodes (whether the cluster will attempt to boot nodes that have
          not be previously defined)
       - default_distro (change the default distro)
       - influx_token (change the token used by InfluxDB and Grafana, parts of the
          ClusterWare monitoring and alerting system)
       - cluster_name (change the name of the cluster)
       - cluster_id (change the Penguin Solutions cluster ID number)
       - auth_config (change settings needed by the authentication system)

GET /cluster/database
     Returns a JSON object with information about the underlying ClusterWare database.
     This endpoint is public and does not require an authentication token.

GET /cluster/summary
     Returns a JSON object with a list of all object UIDs for all ClusterWare object
     types.

GET /cluster/usage
     Returns a JSON object with cluster-wide usage information; this requires that a
     cluster accounting system be configured

GET /cluster/time
     Returns a JSON object with the current time on the head node. This endpoint is
     public and does not require an authentication token.

GET /cluster/accountant
     Returns a JSON object with the current cluster accounting configuration

PUT /cluster/accountant
     Used to set the cluster accounting configuration; this is an advanced topic,
     please contact Penguin Solutions for more information.

GET /cluster/head/{uid}
     Returns a JSON object with information about the specified head node.

GET /cluster/head/{uid}/log
     Returns a JSON object with information about logs from the specified head node.

GET /cluster/hosts
     Returns a JSON object with hostname-ipaddress pairs for all known nodes in the
     cluster. This endpoint is public and does not require an authentication token.

GET /cluster/sshkeys
     Returns a JSON object with information about the authorized keys for the cluster.
     This endpoint is public and does not require an authentication token.

GET /cluster/cabundle
     Returns a JSON object with information about the CA certificates for the cluster.
     This endpoint is public and does not require an authentication token.

GET /cluster/license
     Returns a JSON object with information about the ClusterWare license for this
     cluster.

GET /whoami
     Returns a JSON object identifying the current user

GET /whereami
     Returns a JSON object identifying where (what node) the current user is attaching
     from; this assumes that ClusterWare knows the server (that is, it’s a compute node
     registered in the system)

Head Node Endpoints

ClusterWare stores head nodes objects in the database to assist with management and maintenance.

Data Fields

Head nodes have several fields:

uid
     Required: A unique ID usually configured via a file on disk (base.ini)

ssh_public
     Required: The SSH public key for this head node

description
     Optional: A text string with descriptive information

ca_pem
     Optional: A CA certificate

Additional Endpoints

Several endpoints can be used to interact with the head nodes:

GET /heads/down
     Returns a JSON object with a list of all currently down head nodes

DELETE /heads/down
     Deletes any currently down head nodes, removing them from the cluster; returns a
     JSON object with a list of head nodes that were removed

GET /head/services
     Returns a list of all ClusterWare services and their current status (up or down).
     This endpoint does not require an authentication token, but requires that the
     connection come from another known head node

POST /head/services
     accepts a JSON object with “status” and “services” keys (both required); status
     must be a comma-separated list of: 'start', 'stop', 'restart', 'enable', 'disable',
     'reload'; and services must be a list of one or more head node services (e.g.
     from a call to GET /head/services).  This endpoint does not require an
     authentication token, but requires that the connection come from another known
     head node

GET /head/peerurl
     Returns a JSON object with the peer URL for attaching a new head to the cluster.
     This endpoint is public and does not require an authentication token

GET /head/files/unused
     Returns a list of all ClusterWare-managed files (images, ISOs, etc.) that are
     currently unused. This endpoint does not require an authentication token, but
     requires that the connection come from another known head node

DELETE  /head/files/unused
     Deletes any currently unused files, removing them from the cluster; returns a
     JSON object with a list of files that were removed. This endpoint does not require
     an authentication token, but requires that the connection come from another known
     head node

GET /database/clean
     Returns a JSON object with information about what a database “cleaning” would do
     (but does not perform the cleaning)

POST /database/clean
     Performs database cleaning on the head node and returns a JSON object with
     information about what was performed

POST /database/leave
     Requests that this head node leave the cluster.  This endpoint does not require
     an authentication token, but requires that the connection come from another known
     head node

Caution

This action may cause significant disruption to a running cluster; contact Penguin Solutions for additional information or assistance.

Boot-time Support Endpoints

Several endpoints are designed to support low-level boot-time processes like kickstart, ztp, and ignition:

GET /kickstart/<NAME>
     Returns the kickstart file with the given name; the file must already exist and
     be located in the /opt/scyld/clusterware/kickstarts directory.  The
     output format is different from other ClusterWare commands – there are no
     “success” or “data” keys, just the (text) file. This endpoint is public and does
     not require an authentication token

GET /ztp/script
     Returns a ZTP script or config file for a given node; the node is determined by
     the incoming connection’s IP address and the node must have its “_boot_config”
     attribute set to "ztp:<ZTP_SCRIPTNAME>“. The script must already exist and be
     located in the /opt/scyld/clusterware/kickstarts directory. The output
     format is different from other ClusterWare commands – there are no “success” or
     “data” keys, just the (text) file. This endpoint is public and does not require
     an authentication token

GET /ignition/bin
     Returns the ignition binary for use by the booting node.  The output
     format is different from other ClusterWare commands – there are no “success” or
     “data” keys, just the (text) file. This endpoint is public and does not require
     an authentication token

GET /ignition/<UID>
     Returns the ignition configuration file for the node identified by UID; the node
     must have its “_ignition” attribute set to the configuration to use. That
     configuration may be a URL, a git repo URL, or a locally hosted config file. The
     file must already exist and be located in the /opt/scyld/clusterware/kickstarts
     directory.  The output format is different from other ClusterWare
     commands – there are no “success” or “data” keys, just the (text) file. This
     endpoint is public and does not require an authentication token

GET /install/head/scyld-install
     Returns a `scyld-install` script that can be used to join a server to the current
     head node. This may be useful when automating the creation of multi-head clusters.
    The output format is different from other ClusterWare commands – there
     are no “success” or “data” keys, just the (text) file. This endpoint is public
     and does not require an authentication token

POST /install/password
     Accepts a JSON object with an “admin_pass” key and value and verifies that
     the password is correct for access to the ClusterWare database. This may be
     useful when automating the creation of multi-head clusters. This endpoint is
     public and does not require an authentication token

GET /install/repo
     Returns a JSON object with a data field containing a repository configuration
     suitable for another head node.  This may be useful when automating the creation
     of multi-head clusters. This endpoint is public and does not require an
     authentication token

GET /install/client/installer
     Returns a shell script that can be used to install a system with the ClusterWare
     node package and related monitoring packages.  If requested with no parameters,
     a “pre-installation” script will be returned that will attempt to find out the CPU
     architecture, OS name, and software packaging system.  Alternatively, send the
     following HTTP parameters and get a more customized installer script: ::

             cpu=x86_64
                specify the CPU architecture; one of x86_64 or aarm64
                 os=rhel8
                specify the OS; one of rhel, debian, cumulus, or sonic
                 pkg=tar
                specify the software packaging system; one of tar, rpm, or deb

     If one or more parameters are omitted, then the system will select the installer
     that best matches the set of parameters that were sent.  Clients must be aware
     that a different packaging system may be returned; for example, requesting the
     rpm installer may return a tar-based installer instead.

GET /install/client/download/<PKGSYS>/<NAME>
     Downloads the package named NAME from the head node, where the packaging
     system is determined by PKGSYS.  PKGSYS is one of tar, rpm, or deb.  Note that
     this simply downloads the package and does not install it.