The PVC HTTP API client is built with Flask, a Python framework for creating API interfaces, and run directly with the PyWSGI framework. It interfaces directly with the Zookeeper cluster to send and receive information about the cluster. It supports authentication configured statically via tokens in the configuration file as well as SSL.
The [`pvc-ansible`](https://github.com/parallelvirtualcluster/pvc-ansible) framework will install and configure the API by default, and enable the node daemon option for an instance of the API to follow the primary node, thus ensuring the API is listening on the upstream floating IP at all times.
The API accepts SSL certificate and key files via the `pvc-api.yaml` configuration to enable SSL support for the API, which protects the data and query values from snooping or tampering. SSL is strongly recommended if using the API outside of a trusted local area network.
Authentication for the API is available using a static list of tokens. These tokens can be any long string, but UUIDs are typical and simple to use. Within `pvc-ansible`, the list of tokens can be specified in the `pvc.yml``group_vars` file. Usually, you'd want one token for each user of the API, such as a WebUI, a 3rd-party client, or an administrative user. Within the configuration, each token can have a description; this is mostly for administrative clarity and is not actually used within the API itself.
The API provides session-based login using the `/api/v1/auth/login` and `/api/v1/auth/logout` options. If authentication is not enabled, these endpoints return a JSON `message` of `Authentiation is disabled` and HTTP code 200.
For one-time authentication, the `token` value can be specified to any API endpoint. This is only checked if there is no valid session already established. If authentication is enabled, there is no valid session, and no `token` value is specified, the API will return a JSON `message` of `Authentication required` and HTTP code 401.
The PVC API consistently accepts values (variables) as either HTTP query string arguments, or as HTTP POST form body arguments, in either GET or POST mode.
Some values are `flag_` values; these do not require a data component, and signal an option by their presence.
The PVC API consistently accepts HTTP POST commands of HTML form documents. However, since all form arguments can also be specified as query parameters, and only the `vm define` endpoint accepts a significant amount of data in one argument, it should generally be compatible with API clients speaking only JSON - these can simply send no data in the body and send all required values as query parameters.
The PCI API consistently returns JSON bodies as its responses, with the one exception of the `vm dump` endpoint which returns an XML body. For all POST endpoints, unless otherwise specified below, this is a `message` value containing a human-readable message about the success or failure of the command. The HTTP return code is always 200 for a success or 510 for a failure. For all GET endpoints except the mentioned `vm dump`, this is a JSON body containing the requested data.
Return a JSON `message` containing the API description with HTTP return code 209. Useful for determining if the API is listening and responding properly.
On `GET`, return an HTTP login form accepting a token to authorize a Flask session.
On `POST`, compare the specified token to the database and authorize a session. If this comparison fails to find a match, return a JSON `message` of `Authentication failed` and HTTP code 401.
**NOTE:** The `<vm>` variable in all VM endpoints can be either a `name` or a `uuid`. UUIDs are used internally by PVC to track and identify VMs, but are not human-readable, so the clients treat both as equally valid and will automatically determine the `uuid` for any given `name`.
**NOTE:** While included for consistency, the specified `<vm>` value is ignored and the values from the Libvirt XML configuration will be used instead.
`xml` must be a valid Libvirt XML definition; human-readable, multi-line formatted definitions are fully supported.
If `node` is specified and is valid, the VM will be assigned to `node` instead of automatically determining the target node. If `node` is specified and not valid, return a failure.
If `selector` is specified, the automatic node determination will use `selector` to determine the optimal node instead of the default (`mem`, least allocated VM memory). If `node` is also specified, this value is ignored.
Permanently move (do not track previous node) the VM with name or UUID `<vm>`. Use Libvirt live migration if possible; otherwise `shutdown` then `start` on the new node.
If `node` is specified and is valid, the VM will be assigned to `node` instead of automatically determining the target node. If `node` is specified and not valid, return a failure.
If `selector` is specified, the automatic node determination will use `selector` to determine the optimal node instead of the default (`mem`, least allocated VM memory). If `node` is also specified, this value is ignored.
Temporarily move (track the previous node and migrated state) the VM with name or UUID `<vm>`. Use Libvirt live migration if possible; otherwise `shutdown` then `start` on the new node.
If `node` is specified and is valid, the VM will be assigned to `node` instead of automatically determining the target node. If `node` is specified and not valid, return a failure.
If `selector` is specified, the automatic node determination will use `selector` to determine the optimal node instead of the default (`mem`, least allocated VM memory). If `node` is also specified, this value is ignored.
Attempting to `migrate` an already-migrated VM will return a failure.
If `flag_force` is specified, migrate the VM even if it has already been migrated. The previous node value will not be replaced; e.g. if VM `test` was on `pvchv1`, then `migrate`ed to `pvchv2`, then `flag_force``migrate`ed to `pvchv3`, the `previous_node` would still be `pvchv1`. This can be repeated indefinitely.
Unmigrate the `migrate`ed VM with name or UUID `<vm>`, returning it to its previous node. Use Libvirt live migration if possible; otherwise `shutdown` then `start` on the previous node.
`domain` specifies a DNS domain for hosts in the network. DNS is aggregated and provded for all networks on the primary coordinator node.
`ip4_network` specifies a CIDR-formatted IPv4 netblock, usually RFC1918, for the network.
`ip4_gateway` specifies an IP address from the `ip4_network` for the primary coordinator node to provide gateway services to the network. If `ip4_network` is specified but `ip4_gateway` is not specified or is invalid, return a failure.
`ip6_network` specifies a CIDR-formatted IPv6 netblock for the network.
`ip6_gateway` specifies an IP address from the `ip6_network` for the primary coordinator node to provide gateway services to the network. If `ip6_network` is specified but `ip6_gateway` is not specified or is invalid, default to `<ip6_network>::1`.
`flag_dhcp4` specifies that DHCPv4 should be used for the IPv4 network.
`dhcp4_start` specifies an IP address for the start of the DHCPv4 IP pool. If `flag_dhcp4` is specified but `dhcp4_start` is not specified or is invalid, return a failure.
`dhcp4_end` specifies an IP address for the end of the DHCPv4 IP pool. If `flag_dhcp4` is specified but `dhcp4_end` is not specified or is invalid, return a failure.
**NOTE:** Changing the `vni` or `nettype` of a virtual network is technically possible, but is not recommended. This would require updating all VMs in the network. It is usually advisable to create a new virtual network with the new VNI and type, move VMs to it, then finally remove the old virtual network.
If `limit` is specified, return a JSON document containing information about all active DHCP leases with MAC addresses matching `limit` as fuzzy regex.
Return a JSON document containing information about DHCP lease with MAC address `<lease>` in virtual network with description `<network>`. The output is identical to `/api/v1/network/<network>/dhcp?limit=<lease>` without fuzzy regex.
If `<lease>` is not valid, return an empty JSON document.
If `limit` is specified, return a JSON document containing information about all active NFTables ACLs with descriptions matching `limit` as fuzzy regex.
If `direction` is specified and is one of `in` or `out`, return a JSON codument listing all active NFTables ACLs in the specified direction only. If `direction` is invalid, return a failure.
Return a JSON document containing information about NFTables ACL with description `<acl>` in virtual network with description `<network>`. The output is identical to `/api/v1/network/<network>/acl?limit=<acl>` without fuzzy regex.
If `<acl>` is not valid, return an empty JSON document.
Add a new NFTables ACL with description `<acl>` in virtual network with description `<network>`.
`direction` must be one of `in` or `out`.
`rule` must be a valid NFTables rule string. PVC does no special replacements or variables beyond what NFTables itself is capable of. For per-host ACLs, it is usually advisable to use a static DHCP lease as well to control the VM's IP address.
`order` specifies the order of the rule in the current chain. If not specified, the rule will be placed at the end of the rule chain.
**NOTE:** Unlike the other API endpoints, Ceph endpoints will wait until the command completes successfully before returning. This is a safety measure to prevent the critical storage subsystem from going out-of-sync with the PVC Zookeeper database; the cluster objects are only created after the storage subsystem commands complete. Because of this, *be careful with HTTP timeouts when running Ceph commands via the API*. 30s or longer may be required for some commands, especially OSD addition or removal.
Return a JSON document containing information about Ceph OSD with ID `<osd>` in the storage cluster. Unlike other similar endpoints, this is **NOT** equivalent to any limit within the list, since that limit is based off names rather than just the ID.
Remove a Ceph OSD device with ID `<osd>` from the storage cluster.
**NOTE:** This is a command with potentially dangerous unintended consequences that should not be scripted. To acknowledge the danger, the `flag_yes_i_really_mean_it` must be set or the endpoint will return a failure.
**WARNING:** Removing an OSD without first setting it `out` (and letting it flush) triggers an unclean PG recovery. This could potentially cause data loss if other OSDs were to fail or be removed. OSDs should not normally be removed except in the case of failed OSDs during replacement or during a replacement with a larger disk.
Return a JSON document containing information about Ceph RBD pool with name `<pool>`. The output is identical to `/api/v1/ceph/pool?limit=<pool>` without fuzzy regex.
Add a new Ceph RBD pool with name `<pool>` to the storage cluster.
`pgs` must be a valid number of Placement Groups for the pool, taking into account the number of OSDs and the replication of the pool (`copies=3`). `256` is a safe number for 3 nodes and 2 disks per node. This value can be grown later via `ceph` commands as required.
Remove a Ceph RBD pool with name `<pool>` from the storage cluster.
**NOTE:** This is a command with potentially dangerous unintended consequences that should not be scripted. To acknowledge the danger, the `flag_yes_i_really_mean_it` must be set or the endpoint will return a failure.
**WARNING:** Removing an RBD pool will delete all data on that pool, including all Ceph RBD volumes on the pool. Do not run this command lightly and without ensuring the pool is safely removable first.
Return a JSON document containing information about Ceph RBD volume with name `<volume>` in Ceph RBD pool with name `<pool>`. The output is identical to `/api/v1/ceph/volume?pool=<pool>&limit=<volume>` without fuzzy regex.
The various limit options can be combined freely, e.g. one can specify a `volume` without `pool`, which would match all snapshots of the named volume(s) regardless of pool, or a `pool` and `limit` without a `volume`, which would match all named snapshots on any volume in `pool`.
Return a JSON document containing information about Ceph RBD volume snapshot with name `<snapshot>` of Ceph RBD volume with name `<volume>` in Ceph RBD pool with name `<pool>`. The output is identical to `/api/v1/ceph/volume?pool=<pool>&volume=<volume>&limit=<snapshot>` without fuzzy regex.