Refactored many functions to use pointers/references to remove code duplication and improve memory usage. Minor UI changes. Some doxygen comments.

main
xad1 3 years ago
parent 400c838d1c
commit d2f0e9f481

@ -52,11 +52,13 @@ typedef struct {
String health; String health;
} Pool; } Pool;
Node *getNodeInfo(int *numNodes); Node *getNodeInfo(int &numNodes);
Container *getContainerInfo(int *numContainers, String node); Container *getContainerInfo(int &numContainers, const String &node);
VM *getVMInfo(int *numVMs, String node); VM *getVMInfo(int &numVMs, const String &node);
Disk *getDiskInfo(int *numDisks, String node); Disk *getDiskInfo(int &numDisks, const String &node);
Pool *getPoolInfo(int *numPools, String node); Pool *getPoolInfo(int &numPools, const String &node);
typedef void (*ProcessDataCallback)(DynamicJsonDocument&, int&, void*&);
#endif /* JSON_RETRIEVE_H */ #endif /* JSON_RETRIEVE_H */

@ -1,12 +1,12 @@
#ifndef JSON_SEND_H #ifndef JSON_SEND_H
#define JSON_SEND_H #define JSON_SEND_H
#include <Arduino.h> #include <Arduino.h>
void restartVM(String node, int vmid); void restartVM(const String &node, const int &vmid);
void restartContainer(String node, int containerid); void restartContainer(const String &node, const int &containerid);
void startVM(String node, int vmid); void startVM(const String &node, const int &vmid);
void startContainer(String node, int containerid); void startContainer(const String &node, const int &containerid);
void stopVM(String node, int vmid); void stopVM(const String &node, const int &vmid);
void stopContainer(String node, int containerid); void stopContainer(const String &node, const int &containerid);
#endif /* JSON_SEND_H */ #endif /* JSON_SEND_H */

@ -3,10 +3,10 @@
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <json/retrieve.h> #include <json/retrieve.h>
//JsonObject getNode(String name, JsonArray nodes); //JsonObject getNode(String name, JsonArray nodes);
Node getNode(String name); Node getNode(const String &name);
Container getContainer(int id, String node); Container getContainer(const int &id, const String &node);
VM getVM(int id, String node); VM getVM(const int &id, const String &node);
Disk getDisk(String devpath, String node); Disk getDisk(const String &devpath, const String &node);
Pool getPool(String name, String node); Pool getPool(const String &name, const String &node);
#endif /* JSON_UTILS_H */ #endif /* JSON_UTILS_H */

@ -9,15 +9,17 @@ typedef struct {
void (*function)(); void (*function)();
} MenuItem; } MenuItem;
void listNodes(Node* nodes, int numItems); void listNodes(Node* nodes, const int &numItems);
void listContainers(Container* containers, int numItems); void listContainers(Container* containers, const int &numItems);
void listVMs(VM* vms, int numItems); void listVMs(VM* vms, const int &numItems);
void listDisks(Disk* disks, int numItems); void listDisks(Disk* disks, const int &numItems);
void listPools(Pool* pools, int numItems); void listPools(Pool* pools, const int &numItems);
void mainMenu(); void mainMenu();
void manageContainerMenu(); void manageContainerMenu();
void manageVMMenu(); void manageVMMenu();
typedef void (*MenuPrintCallback)(void*);
extern int selectedItem; extern int selectedItem;
extern int selectedPage; extern int selectedPage;

@ -5,163 +5,139 @@
#include <json/retrieve.h> #include <json/retrieve.h>
#include <stdexcept> #include <stdexcept>
Node *getNodeInfo(int *numNodes) /// @brief This is a callback function to process the json data of a node provided by the API into an array of Node structs.
/// @param doc A reference to the json document containing the data from the API.
/// @param numNodes A reference to an integer containing the number of nodes retrieved from the API.
/// @param nodeArray A pointer to the array used to hold the nodes once they have been processed.
void processNodeData(DynamicJsonDocument &doc, int &numNodes, void *&nodeArray)
{ {
HTTPClient http; JsonArray nodes = doc["data"].as<JsonArray>();
String apiAddress = PROXMOX_ADDRESS + "/api2/json/nodes/"; Node *array = new Node[nodes.size()];
String auth = "PVEAPIToken=" + PROXMOX_TOKEN_USER + "!" + PROXMOX_TOKEN_NAME + "=" + PROXMOX_TOKEN_SECRET;
char authc[auth.length() + 1];
auth.toCharArray(authc, auth.length() + 1);
http.begin(apiAddress);
http.setAuthorization(authc);
int httpCode = http.GET();
if (httpCode > 0) for (int i = 0; i < nodes.size(); i++)
{ {
String json = http.getString(); array[i].name = nodes[i]["node"].as<String>();
DynamicJsonDocument doc(8096); array[i].cpu = nodes[i]["cpu"].as<float>();
deserializeJson(doc, json); array[i].threads = nodes[i]["maxcpu"].as<int>();
array[i].onlineStatus = nodes[i]["status"].as<String>();
array[i].mem = nodes[i]["mem"].as<long long>();
array[i].maxmem = nodes[i]["maxmem"].as<long long>();
array[i].disk = nodes[i]["disk"].as<long long>();
array[i].maxdisk = nodes[i]["maxdisk"].as<long long>();
array[i].uptime = nodes[i]["uptime"].as<long long>();
}
numNodes = nodes.size();
nodeArray = array;
}
JsonArray nodes = doc["data"].as<JsonArray>(); /// @brief This is a callback function to process the json data of a container provided by the api into an array of Container structs.
Node *nodeArray = new Node[nodes.size()]; /// @param doc A reference to the json document containing the data from the API.
/// @param numContainers A reference to an integer containing the number of containers retrieved from the API.
for (int i = 0; i < nodes.size(); i++) /// @param containerArray A pointer to the array used to hold the containers once they have been processed.
{ void processContainerData(DynamicJsonDocument &doc, int &numContainers, void *&containerArray)
nodeArray[i].name = nodes[i]["node"].as<String>(); {
nodeArray[i].cpu = nodes[i]["cpu"].as<float>(); JsonArray containers = doc["data"].as<JsonArray>();
nodeArray[i].threads = nodes[i]["maxcpu"].as<int>(); Container *array = new Container[containers.size()];
nodeArray[i].onlineStatus = nodes[i]["status"].as<String>();
nodeArray[i].mem = nodes[i]["mem"].as<long long>(); for (int i = 0; i < containers.size(); i++)
nodeArray[i].maxmem = nodes[i]["maxmem"].as<long long>(); {
nodeArray[i].disk = nodes[i]["disk"].as<long long>(); array[i].name = containers[i]["name"].as<String>();
nodeArray[i].maxdisk = nodes[i]["maxdisk"].as<long long>(); array[i].id = containers[i]["vmid"].as<int>();
nodeArray[i].uptime = nodes[i]["uptime"].as<long long>(); array[i].onlineStatus = containers[i]["status"].as<String>();
} array[i].maxmem = containers[i]["maxmem"].as<long long>();
array[i].maxdisk = containers[i]["maxdisk"].as<long long>();
*numNodes = nodes.size(); array[i].uptime = containers[i]["uptime"].as<long long>();
return nodeArray;
} }
throw std::runtime_error("Can't get node info: HTTP request failed with code: " + httpCode);
numContainers = containers.size();
containerArray = array;
} }
Container *getContainerInfo(int *numContainers, String node) /// @brief This is a callback function to process the json data of a VM provided by the api into an array of VM structs.
/// @param doc A reference to the json document containing the data from the API.
/// @param numVMs A reference to an integer containing the number of VMs retrieved from the API.
/// @param vmArray A pointer to the array used to hold the VMs once they have been processed.
void processVMData(DynamicJsonDocument &doc, int &numVMs, void *&vmArray)
{ {
HTTPClient http; JsonArray vms = doc["data"].as<JsonArray>();
String apiAddress = PROXMOX_ADDRESS + "/api2/json/nodes/" + node + "/lxc"; VM *array = new VM[vms.size()];
String auth = "PVEAPIToken=" + PROXMOX_TOKEN_USER + "!" + PROXMOX_TOKEN_NAME + "=" + PROXMOX_TOKEN_SECRET;
char authc[auth.length() + 1];
auth.toCharArray(authc, auth.length() + 1);
http.begin(apiAddress);
http.setAuthorization(authc);
int httpCode = http.GET();
if (httpCode > 0) for (int i = 0; i < vms.size(); i++)
{ {
String json = http.getString(); array[i].name = vms[i]["name"].as<String>();
DynamicJsonDocument doc(8096); array[i].id = vms[i]["vmid"].as<int>();
deserializeJson(doc, json); array[i].onlineStatus = vms[i]["status"].as<String>();
JsonArray containers = doc["data"].as<JsonArray>(); array[i].maxmem = vms[i]["maxmem"].as<long long>();
Container *containerArray = new Container[containers.size()]; array[i].maxdisk = vms[i]["maxdisk"].as<long long>();
array[i].uptime = vms[i]["uptime"].as<long long>();
for (int i = 0; i < containers.size(); i++) array[i].netin = vms[i]["netin"].as<long long>();
{ array[i].netout = vms[i]["netout"].as<long long>();
containerArray[i].name = containers[i]["name"].as<String>();
containerArray[i].id = containers[i]["vmid"].as<int>();
containerArray[i].onlineStatus = containers[i]["status"].as<String>();
containerArray[i].maxmem = containers[i]["maxmem"].as<long long>();
containerArray[i].maxdisk = containers[i]["maxdisk"].as<long long>();
containerArray[i].uptime = containers[i]["uptime"].as<long long>();
}
*numContainers = containers.size();
return containerArray;
} }
throw std::runtime_error("Can't get container info: HTTP request failed with code: " + httpCode); numVMs = vms.size();
vmArray = array;
} }
VM *getVMInfo(int *numVMs, String node) /// @brief This is a callback function to process the json data of a disk provided by the api into an array of disk structs.
/// @param doc A reference to the json document containing the data from the API.
/// @param numDisks A reference to an integer containing the number of disks retrieved from the API.
/// @param diskArray A pointer to the array used to hold the disks once they have been processed.
void processDiskData(DynamicJsonDocument &doc, int &numDisks, void *&diskArray)
{ {
HTTPClient http; JsonArray disks = doc["data"].as<JsonArray>();
String apiAddress = PROXMOX_ADDRESS + "/api2/json/nodes/" + node + "/qemu"; Disk *array = new Disk[disks.size()];
String auth = "PVEAPIToken=" + PROXMOX_TOKEN_USER + "!" + PROXMOX_TOKEN_NAME + "=" + PROXMOX_TOKEN_SECRET;
char authc[auth.length() + 1];
auth.toCharArray(authc, auth.length() + 1);
http.begin(apiAddress);
http.setAuthorization(authc);
int httpCode = http.GET();
if (httpCode > 0) for (int i = 0; i < disks.size(); i++)
{ {
String json = http.getString(); array[i].devpath = disks[i]["devpath"].as<String>();
DynamicJsonDocument doc(8096); array[i].size = disks[i]["size"].as<long long>();
deserializeJson(doc, json); array[i].used = disks[i]["used"].as<String>();
JsonArray vms = doc["data"].as<JsonArray>(); array[i].serial = disks[i]["serial"].as<String>();
VM *vmArray = new VM[vms.size()]; array[i].model = disks[i]["model"].as<String>();
array[i].vendor = disks[i]["vendor"].as<String>();
for (int i = 0; i < vms.size(); i++) array[i].health = disks[i]["health"].as<String>();
{
vmArray[i].name = vms[i]["name"].as<String>();
vmArray[i].id = vms[i]["vmid"].as<int>();
vmArray[i].onlineStatus = vms[i]["status"].as<String>();
vmArray[i].maxmem = vms[i]["maxmem"].as<long long>();
vmArray[i].maxdisk = vms[i]["maxdisk"].as<long long>();
vmArray[i].uptime = vms[i]["uptime"].as<long long>();
vmArray[i].netin = vms[i]["netin"].as<long long>();
vmArray[i].netout = vms[i]["netout"].as<long long>();
}
*numVMs = vms.size();
return vmArray;
} }
throw std::runtime_error("Can't get VM info: HTTP request failed with code: " + httpCode);
numDisks = disks.size();
diskArray = array;
} }
Disk *getDiskInfo(int *numDisks, String node) /// @brief This is a callback function to process the json data of a ZFS pool provided by the api into an array of Pool structs.
/// @param doc A reference to the json document containing the data from the API.
/// @param numPools A reference to an integer containing the number of pools retrieved from the API.
/// @param poolArray A pointer to the array used to hold the pools once they have been processed.
void processPoolData(DynamicJsonDocument &doc, int &numPools, void *&poolArray)
{ {
HTTPClient http; JsonArray pools = doc["data"].as<JsonArray>();
String apiAddress = PROXMOX_ADDRESS + "/api2/json/nodes/" + node + "/disks/list"; Pool *array = new Pool[pools.size()];
String auth = "PVEAPIToken=" + PROXMOX_TOKEN_USER + "!" + PROXMOX_TOKEN_NAME + "=" + PROXMOX_TOKEN_SECRET;
char authc[auth.length() + 1];
auth.toCharArray(authc, auth.length() + 1);
http.begin(apiAddress);
http.setAuthorization(authc);
int httpCode = http.GET();
if (httpCode > 0) for (int i = 0; i < pools.size(); i++)
{ {
String json = http.getString(); array[i].name = pools[i]["name"].as<String>();
DynamicJsonDocument doc(32768); array[i].free = pools[i]["free"].as<long long>();
deserializeJson(doc, json); array[i].size = pools[i]["size"].as<long long>();
JsonArray disks = doc["data"].as<JsonArray>(); array[i].health = pools[i]["health"].as<String>();
Disk *diskArray = new Disk[disks.size()];
for (int i = 0; i < disks.size(); i++)
{
Serial.println(disks[i]["devpath"].as<String>());
diskArray[i].devpath = disks[i]["devpath"].as<String>();
diskArray[i].size = disks[i]["size"].as<long long>();
diskArray[i].used = disks[i]["used"].as<String>();
diskArray[i].serial = disks[i]["serial"].as<String>();
diskArray[i].model = disks[i]["model"].as<String>();
diskArray[i].vendor = disks[i]["vendor"].as<String>();
diskArray[i].health = disks[i]["health"].as<String>();
}
*numDisks = disks.size();
return diskArray;
} }
throw std::runtime_error("Can't get disk info: HTTP request failed with code: " + httpCode);
numPools = pools.size();
poolArray = array;
} }
Pool *getPoolInfo(int *numPools, String node) /// @brief This is the main function to retrieve data from the API. Is is a generic function to handle retrieving all the data for the program.
/// @tparam T The type of the item being retrieved.
/// @param apiAddress The API path to get the appropriate data.
/// @param numItems A reference to an integer to store the number of items retrieved from the API.
/// @param processData A callback function to process the data coming in from the API.
/// @return The array of items populated by the process function is returned in the type defined by T.
template <typename T>
T *apiCall(const String &apiAddress, int &numItems, ProcessDataCallback processData)
{ {
HTTPClient http; HTTPClient http;
String apiAddress = PROXMOX_ADDRESS + "/api2/json/nodes/" + node + "/disks/zfs"; http.begin(PROXMOX_ADDRESS + apiAddress);
String auth = "PVEAPIToken=" + PROXMOX_TOKEN_USER + "!" + PROXMOX_TOKEN_NAME + "=" + PROXMOX_TOKEN_SECRET; String auth = "PVEAPIToken=" + PROXMOX_TOKEN_USER + "!" + PROXMOX_TOKEN_NAME + "=" + PROXMOX_TOKEN_SECRET;
char authc[auth.length() + 1]; char authc[auth.length() + 1];
auth.toCharArray(authc, auth.length() + 1); auth.toCharArray(authc, auth.length() + 1);
http.begin(apiAddress);
http.setAuthorization(authc); http.setAuthorization(authc);
int httpCode = http.GET(); int httpCode = http.GET();
@ -170,19 +146,60 @@ Pool *getPoolInfo(int *numPools, String node)
String json = http.getString(); String json = http.getString();
DynamicJsonDocument doc(32768); DynamicJsonDocument doc(32768);
deserializeJson(doc, json); deserializeJson(doc, json);
JsonArray pools = doc["data"].as<JsonArray>();
Pool *poolArray = new Pool[pools.size()]; void *itemArray = nullptr;
processData(doc, numItems, itemArray);
for (int i = 0; i < pools.size(); i++)
{ return static_cast<T *>(itemArray);
poolArray[i].name = pools[i]["name"].as<String>();
poolArray[i].free = pools[i]["free"].as<long long>();
poolArray[i].size = pools[i]["size"].as<long long>();
poolArray[i].health = pools[i]["health"].as<String>();
}
*numPools = pools.size();
return poolArray;
} }
throw std::runtime_error("Can't get pool info: HTTP request failed with code: " + httpCode); throw std::runtime_error("HTTP request failed with code: " + httpCode);
} }
/// @brief Function to retrieve node data from the API. Calls the apiCall() function with the appropriate parameters for nodes.
/// @param numNodes A reference to an integer to hold the number of nodes retrieved.
/// @return The array of nodes created by the apiCall() function.
Node *getNodeInfo(int &numNodes)
{
String apiAddress = "/api2/json/nodes/";
return apiCall<Node>(apiAddress, numNodes, processNodeData);
}
/// @brief Function to retrieve container data from the API. Calls the apiCall() function with the appropriate parameters for containers.
/// @param numContainers A reference to an integer to hold the number of containers retrieved.
/// @param node A reference to a string which defines which node we are retrieving container data from.
/// @return The array of containers created by the apiCall() function.
Container *getContainerInfo(int &numContainers, const String &node)
{
String apiAddress = "/api2/json/nodes/" + node + "/lxc";
return apiCall<Container>(apiAddress, numContainers, processContainerData);
}
/// @brief Function to retrieve VM data from the API. Calls the apiCall() function with the appropriate parameters for VMs.
/// @param numVMs A reference to an integer to hold the number of VMs retrieved.
/// @param node A reference to a string which defines which node we are retrieving VM data from.
/// @return The array of VMs created by the apiCall() function.
VM *getVMInfo(int &numVMs, const String &node)
{
String apiAddress = "/api2/json/nodes/" + node + "/qemu";
return apiCall<VM>(apiAddress, numVMs, processVMData);
}
/// @brief Function to retrieve disk data from the API. Calls the apiCall() function with the appropriate parameters for disks.
/// @param numDisks A reference to an integer to hold the number of disks retrieved.
/// @param node A reference to a string which defines which node we are retrieving disk data from.
/// @return The array of disks created by the apiCall() function.
Disk *getDiskInfo(int &numDisks, const String &node)
{
String apiAddress = "/api2/json/nodes/" + node + "/disks/list";
return apiCall<Disk>(apiAddress, numDisks, processDiskData);
}
/// @brief Function to retrieve pool data from the API. Calls the apiCall() function with the appropriate parameters for pools.
/// @param numPools A reference to an integer to hold the number of pools retrieved.
/// @param node A reference to a string which defines which node we are retrieving pool data from.
/// @return The array of pools created by the apiCall() function.
Pool *getPoolInfo(int &numPools, const String &node)
{
String apiAddress = "/api2/json/nodes/" + node + "/disks/zfs";
return apiCall<Pool>(apiAddress, numPools, processPoolData);
}

@ -5,10 +5,12 @@
#include <json/retrieve.h> #include <json/retrieve.h>
#include <stdexcept> #include <stdexcept>
void restartVM(String node, int vmid) /// @brief This is a function to send data to the API. Used for commands such as restarting. It also supports including a post payload to send additional information the API.
{ /// @param apiPath Refrence to a string which holds the appropriate path on the API to send data.
/// @param post Reference to a string which contains a payload to send to the API.
void apiSend(const String &apiPath, const String &post) {
HTTPClient http; HTTPClient http;
String apiAddress = PROXMOX_ADDRESS + "/api2/json/nodes/" + node + "/qemu/" + vmid + "/status/reboot"; String apiAddress = PROXMOX_ADDRESS + apiPath;
String auth = "PVEAPIToken=" + PROXMOX_TOKEN_USER + "!" + PROXMOX_TOKEN_NAME + "=" + PROXMOX_TOKEN_SECRET; String auth = "PVEAPIToken=" + PROXMOX_TOKEN_USER + "!" + PROXMOX_TOKEN_NAME + "=" + PROXMOX_TOKEN_SECRET;
char authc[auth.length() + 1]; char authc[auth.length() + 1];
auth.toCharArray(authc, auth.length() + 1); auth.toCharArray(authc, auth.length() + 1);
@ -18,91 +20,61 @@ void restartVM(String node, int vmid)
http.end(); http.end();
if(httpCode == 0) { if(httpCode == 0) {
throw std::runtime_error("Can't restart VM. Error code: " + httpCode); throw std::runtime_error("Can't stop. Error code: " + httpCode);
} }
} }
void restartContainer(String node, int containerid) /// @brief The function to restart a given VM. Calls the apiSend() function with the appropriate parameters to restart a VM.
/// @param node A reference to a string which contains the name of the node that is running the VM that is being restarted.
/// @param vmid A reference to an integer which holds the ID of the VM being restarted.
void restartVM(const String &node, const int &vmid)
{ {
HTTPClient http; String apiPath = "/api2/json/nodes/" + node + "/qemu/" + vmid + "/status/reboot";
String apiAddress = PROXMOX_ADDRESS + "/api2/json/nodes/" + node + "/lxc/" + containerid + "/status/reboot"; apiSend(apiPath, "");
String auth = "PVEAPIToken=" + PROXMOX_TOKEN_USER + "!" + PROXMOX_TOKEN_NAME + "=" + PROXMOX_TOKEN_SECRET;
char authc[auth.length() + 1];
auth.toCharArray(authc, auth.length() + 1);
http.begin(apiAddress);
http.setAuthorization(authc);
int httpCode = http.POST("");
http.end();
if(httpCode == 0) {
throw std::runtime_error("Can't restart container. Error code: " + httpCode);
}
} }
void startVM(String node, int vmid) /// @brief The function to restart a given container. Calls the apiSend() function with the appropriate parameters to restart a container.
/// @param node A reference to a string which contains the name of the node that is running the container that is being restarted.
/// @param containerid A reference to an integer which holds the ID of the container being restarted.
void restartContainer(const String &node, const int &containerid)
{ {
HTTPClient http; String apiPath = "/api2/json/nodes/" + node + "/lxc/" + containerid + "/status/reboot";
String apiAddress = PROXMOX_ADDRESS + "/api2/json/nodes/" + node + "/qemu/" + vmid + "/status/start"; apiSend(apiPath, "");
String auth = "PVEAPIToken=" + PROXMOX_TOKEN_USER + "!" + PROXMOX_TOKEN_NAME + "=" + PROXMOX_TOKEN_SECRET;
char authc[auth.length() + 1];
auth.toCharArray(authc, auth.length() + 1);
http.begin(apiAddress);
http.setAuthorization(authc);
int httpCode = http.POST("");
http.end();
if(httpCode == 0) {
throw std::runtime_error("Can't start VM. Error code: " + httpCode);
}
} }
void startContainer(String node, int containerid) /// @brief The function to start a given VM. Calls the apiSend() function with the appropriate parameters to start a VM.
/// @param node A reference to a string which contains the name of the node that is running the VM that is being started.
/// @param vmid A reference to an integer which holds the ID of the VM being started.
void startVM(const String &node, const int &vmid)
{ {
HTTPClient http; String apiPath = "/api2/json/nodes/" + node + "/qemu/" + vmid + "/status/start";
String apiAddress = PROXMOX_ADDRESS + "/api2/json/nodes/" + node + "/lxc/" + containerid + "/status/start"; apiSend(apiPath, "");
String auth = "PVEAPIToken=" + PROXMOX_TOKEN_USER + "!" + PROXMOX_TOKEN_NAME + "=" + PROXMOX_TOKEN_SECRET;
char authc[auth.length() + 1];
auth.toCharArray(authc, auth.length() + 1);
http.begin(apiAddress);
http.setAuthorization(authc);
int httpCode = http.POST("");
http.end();
if(httpCode == 0) {
throw std::runtime_error("Can't start container. Error code: " + httpCode);
}
} }
void stopVM(String node, int vmid) /// @brief The function to start a given container. Calls the apiSend() function with the appropriate parameters to start a container.
/// @param node A reference to a string which contains the name of the node that is running the container that is being started.
/// @param containerid A reference to an integer which holds the ID of the container being started.
void startContainer(const String &node, const int &containerid)
{ {
HTTPClient http; String apiPath = "/api2/json/nodes/" + node + "/lxc/" + containerid + "/status/start";
String apiAddress = PROXMOX_ADDRESS + "/api2/json/nodes/" + node + "/qemu/" + vmid + "/status/stop"; apiSend(apiPath, "");
String auth = "PVEAPIToken=" + PROXMOX_TOKEN_USER + "!" + PROXMOX_TOKEN_NAME + "=" + PROXMOX_TOKEN_SECRET;
char authc[auth.length() + 1];
auth.toCharArray(authc, auth.length() + 1);
http.begin(apiAddress);
http.setAuthorization(authc);
int httpCode = http.POST("");
http.end();
if(httpCode == 0) {
throw std::runtime_error("Can't stop VM. Error code: " + httpCode);
}
} }
void stopContainer(String node, int containerid) /// @brief The function to stop a given VM. Calls the apiSend() function with the appropriate parameters to stop a VM.
/// @param node A reference to a string which contains the name of the node that is running the VM that is being stopped.
/// @param vmid A reference to an integer which holds the ID of the VM being stopped.
void stopVM(const String &node, const int &vmid)
{ {
HTTPClient http; String apiPath = "/api2/json/nodes/" + node + "/qemu/" + vmid + "/status/stop";
String apiAddress = PROXMOX_ADDRESS + "/api2/json/nodes/" + node + "/lxc/" + containerid + "/status/stop"; apiSend(apiPath, "");
String auth = "PVEAPIToken=" + PROXMOX_TOKEN_USER + "!" + PROXMOX_TOKEN_NAME + "=" + PROXMOX_TOKEN_SECRET; }
char authc[auth.length() + 1];
auth.toCharArray(authc, auth.length() + 1);
http.begin(apiAddress);
http.setAuthorization(authc);
int httpCode = http.POST("");
http.end();
if(httpCode == 0) { /// @brief The function to stop a given container. Calls the apiSend() function with the appropriate parameters to stop a container.
throw std::runtime_error("Can't stop container. Error code: " + httpCode); /// @param node A reference to a string which contains the name of the node that is running the container that is being stopped.
} /// @param containerid A reference to an integer which holds the ID of the container being stopped.
} void stopContainer(const String &node, const int &containerid)
{
String apiPath = "/api2/json/nodes/" + node + "/lxc/" + containerid + "/status/stop";
apiSend(apiPath, "");
}

@ -3,43 +3,58 @@
#include <utils.h> #include <utils.h>
#include <stdexcept> #include <stdexcept>
Node getNode(String name) /// @brief Function to retrieve a specific node. Retrieves an array of the nodes and uses a for loop to check the name of each one until it finds one that matches the provided name.
/// @param name A reference to a string containing the name of the node being searched for.
/// @return The node which matches the name provided.
Node getNode(const String &name)
{ {
int numNodes; int numNodes;
Node *nodes = getNodeInfo(&numNodes); Node *nodes = getNodeInfo(numNodes);
for (int i = 0; i < numNodes; i++) for (int i = 0; i < numNodes; i++)
{ {
if (nodes[i].name == name) if (nodes[i].name == name)
{ {
return nodes[i]; Node node = nodes[i];
delete[] nodes;
return node;
} }
} }
throw std::runtime_error("Can't find the requested node in the array"); throw std::runtime_error("Can't find the requested node in the array");
} }
Container getContainer(int id, String node) /// @brief Function to retrieve a specific container. Retrieves an array of the containers and uses a for loop to check the id of each one until it finds one that matches the provided id.
/// @param id A reference to an integer which contains the id of the container being searched for.
/// @param node A reference to a string which contains the name of the node being searched on.
/// @return A container that matches the id provided.
Container getContainer(const int &id, const String &node)
{ {
int numContainers; int numContainers;
Container *containers = getContainerInfo(&numContainers, node); Container *containers = getContainerInfo(numContainers, node);
for (int i = 0; i < numContainers; i++) for (int i = 0; i < numContainers; i++)
{ {
if (containers[i].id == id) if (containers[i].id == id)
{ {
return containers[i]; Container container = containers[i];
delete[] containers;
return container;
} }
} }
throw std::runtime_error("Can't find the requested container in the array"); throw std::runtime_error("Can't find the requested container in the array");
} }
VM getVM(int id, String node) /// @brief Function to retrieve a specific VM. Retrieves an array of the VMs and uses a for loop to check the id of each one until it finds one that matches the provided id.
/// @param id A reference to an integer which contains the id of the VM being searched for.
/// @param node A reference to a string which contains the name of the node being searched on.
/// @return A VM that matches the id provided.
VM getVM(const int &id, const String &node)
{ {
int numVMs; int numVMs;
VM *vms = getVMInfo(&numVMs, node); VM *vms = getVMInfo(numVMs, node);
for (int i = 0; i < numVMs; i++) for (int i = 0; i < numVMs; i++)
{ {
if (vms[i].id == id) if (vms[i].id == id)
@ -51,11 +66,15 @@ VM getVM(int id, String node)
throw std::runtime_error("Can't find the requested vm in the array"); throw std::runtime_error("Can't find the requested vm in the array");
} }
Disk getDisk(String devpath, String node) /// @brief Function to retrieve a specific disk. Retrieves an array of the containers and uses a for loop to check the devpath (e.g /dev/sda) of each one until it finds one that matches the provided devpath.
/// @param devpath A reference to a string which contains the devpath of the container being searched for.
/// @param node A reference to a string which contains the name of the node being searched on.
/// @return A disk that matches the devpath provided.
Disk getDisk(const String &devpath, const String &node)
{ {
int numDisks; int numDisks;
Disk *disks = getDiskInfo(&numDisks, node); Disk *disks = getDiskInfo(numDisks, node);
for (int i = 0; i < numDisks; i++) for (int i = 0; i < numDisks; i++)
{ {
if (disks[i].devpath == devpath) if (disks[i].devpath == devpath)
@ -67,11 +86,15 @@ Disk getDisk(String devpath, String node)
throw std::runtime_error("Can't find the requested disk in the array"); throw std::runtime_error("Can't find the requested disk in the array");
} }
Pool getPool(String name, String node) /// @brief Function to retrieve a specific ZFS pool. Retrieves an array of the pools and uses a for loop to check the name of each one until it finds one that matches the provided name.
/// @param name A reference to a string which contains the name of the pool being searched for.
/// @param node A reference to a string which contains the name of the node being searched on.
/// @return A pool that matches the name provided.
Pool getPool(const String &name, const String &node)
{ {
int numPools; int numPools;
Pool *pools = getPoolInfo(&numPools, node); Pool *pools = getPoolInfo(numPools, node);
for (int i = 0; i < numPools; i++) for (int i = 0; i < numPools; i++)
{ {
if (pools[i].name == name) if (pools[i].name == name)

@ -10,21 +10,28 @@
void loop() void loop()
{ {
// Check if still connected to a WiFi network. If not then display this to the user and then attempt to reconnect.
if (WiFi.status() != WL_CONNECTED) if (WiFi.status() != WL_CONNECTED)
{ {
displayError("WiFi Connection Lost"); displayError("WiFi Connection Lost");
connectWiFi(); connectWiFi();
} }
//Try catch to handle errors in the program. If an error is found it is displayed to the user before the program continues.
try try
{ {
// Display the list of nodes for the user to choose from.
int numNodes; int numNodes;
Node *nodes = getNodeInfo(&numNodes); Node *nodes = getNodeInfo(numNodes);
listNodes(nodes, numNodes); listNodes(nodes, numNodes);
delete[] nodes; delete[] nodes;
// Reset menu selection variables before continuing to the main menu.
selectedItem = 0; selectedItem = 0;
selectedPage = 0; selectedPage = 0;
mainMenu(); mainMenu();
} }
catch (const std::exception &e) catch (const std::exception &e)
{ {
@ -38,6 +45,11 @@ void setup()
Serial.begin(115200); Serial.begin(115200);
GO.begin(); GO.begin();
GO.lcd.setTextWrap(false); GO.lcd.setTextWrap(false);
/**
* Prompt user to enter pin if one is set. Will only continue if the pin is correct.
* If a pin has not been set then warn the user before continuing.
**/
if (LOCK_PIN != "") if (LOCK_PIN != "")
{ {
bool pinCorrect = false; bool pinCorrect = false;
@ -49,6 +61,6 @@ void setup()
displayError("Warning: No pin set"); displayError("Warning: No pin set");
} }
// Connect to the configured WiFi network.
connectWiFi(); connectWiFi();
Serial.println("done setup");
} }

@ -6,13 +6,14 @@
#include <odroid_go.h> #include <odroid_go.h>
#include <utils.h> #include <utils.h>
/// @brief User interface function to restart a VM. Retrieves an array of all VMs on the selected node, calls the list function to allow the user to pick a VM and then calls the restartVM() function on that VM to send the request to the API. Returns to the manage VM menu afterwards.
void vmRestart() void vmRestart()
{ {
Serial.println("vm restart"); Serial.println("vm restart");
selectedItem = 0; selectedItem = 0;
selectedVM = 0; selectedVM = 0;
int numVMs; int numVMs;
VM *vms = getVMInfo(&numVMs, selectedNode); VM *vms = getVMInfo(numVMs, selectedNode);
listVMs(vms, numVMs); listVMs(vms, numVMs);
delete[] vms; delete[] vms;
if (selectedVM > 0) if (selectedVM > 0)
@ -26,13 +27,14 @@ void vmRestart()
manageVMMenu(); manageVMMenu();
} }
/// @brief User interface function to restart a container. Retrieves an array of all containers on the selected node, calls the list function to allow the user to pick a container and then calls the restartContainer() function on that container to send the request to the API. Returns to the manage container menu afterwards.
void containerRestart() void containerRestart()
{ {
Serial.println("lxc restart"); Serial.println("lxc restart");
selectedItem = 0; selectedItem = 0;
selectedLXC = 0; selectedLXC = 0;
int numContainers; int numContainers;
Container *containers = getContainerInfo(&numContainers, selectedNode); Container *containers = getContainerInfo(numContainers, selectedNode);
listContainers(containers, numContainers); listContainers(containers, numContainers);
delete[] containers; delete[] containers;
if (selectedLXC > 0) if (selectedLXC > 0)
@ -47,14 +49,14 @@ void containerRestart()
manageContainerMenu(); manageContainerMenu();
} }
/// @brief User interface function to start a VM. Retrieves an array of all VMs on the selected node, calls the list function to allow the user to pick a VM and then calls the startVM() function on that VM to send the request to the API. Returns to the manage VM menu afterwards.
void vmStart() void vmStart()
{ {
Serial.println("vm start"); Serial.println("vm start");
selectedItem = 0; selectedItem = 0;
selectedVM = 0; selectedVM = 0;
int numVMs; int numVMs;
VM *vms = getVMInfo(&numVMs, selectedNode); VM *vms = getVMInfo(numVMs, selectedNode);
listVMs(vms, numVMs); listVMs(vms, numVMs);
delete[] vms; delete[] vms;
if (selectedVM > 0) if (selectedVM > 0)
@ -71,13 +73,14 @@ void vmStart()
manageVMMenu(); manageVMMenu();
} }
/// @brief User interface function to start a container. Retrieves an array of all containers on the selected node, calls the list function to allow the user to pick a container and then calls the startContainer() function on that container to send the request to the API. Returns to the manage container menu afterwards.
void containerStart() void containerStart()
{ {
Serial.println("lxc start"); Serial.println("lxc start");
selectedItem = 0; selectedItem = 0;
selectedLXC = 0; selectedLXC = 0;
int numContainers; int numContainers;
Container *containers = getContainerInfo(&numContainers, selectedNode); Container *containers = getContainerInfo(numContainers, selectedNode);
listContainers(containers, numContainers); listContainers(containers, numContainers);
delete[] containers; delete[] containers;
if (selectedLXC > 0) if (selectedLXC > 0)
@ -91,13 +94,15 @@ void containerStart()
manageContainerMenu(); manageContainerMenu();
} }
/// @brief User interface function to stop a VM. Retrieves an array of all VMs on the selected node, calls the list function to allow the user to pick a VM and then calls the startVM() function on that VM to send the request to the API. Returns to the manage VM menu afterwards.
void vmStop() void vmStop()
{ {
Serial.println("vm stop"); Serial.println("vm stop");
selectedItem = 0; selectedItem = 0;
selectedVM = 0; selectedVM = 0;
int numVMs; int numVMs;
VM *vms = getVMInfo(&numVMs, selectedNode); VM *vms = getVMInfo(numVMs, selectedNode);
listVMs(vms, numVMs); listVMs(vms, numVMs);
delete[] vms; delete[] vms;
if (selectedVM > 0) if (selectedVM > 0)
@ -114,13 +119,14 @@ void vmStop()
manageVMMenu(); manageVMMenu();
} }
/// @brief User interface function to stop a container. Retrieves an array of all containers on the selected node, calls the list function to allow the user to pick a container and then calls the stopContainer() function on that container to send the request to the API. Returns to the manage container menu afterwards.
void containerStop() void containerStop()
{ {
Serial.println("lxc stop"); Serial.println("lxc stop");
selectedItem = 0; selectedItem = 0;
selectedLXC = 0; selectedLXC = 0;
int numContainers; int numContainers;
Container *containers = getContainerInfo(&numContainers, selectedNode); Container *containers = getContainerInfo(numContainers, selectedNode);
listContainers(containers, numContainers); listContainers(containers, numContainers);
delete[] containers; delete[] containers;
if (selectedLXC > 0) if (selectedLXC > 0)

@ -6,13 +6,14 @@
#include <global.h> #include <global.h>
#include <manage.h> #include <manage.h>
// UI constants for the menu system.
const int MAIN_TEXT_COLOR = WHITE; const int MAIN_TEXT_COLOR = WHITE;
const int MAIN_TEXT_SIZE = 2; const int MAIN_TEXT_SIZE = 2;
const int ITEMS_PER_PAGE = 12; const int ITEMS_PER_PAGE = 12;
const int OFFLINE_COLOR = RED; const int OFFLINE_COLOR = RED;
const int ONLINE_COLOR = GREEN; const int ONLINE_COLOR = GREEN;
// Initializing variables which hold the selections.
int selectedItem = 0; int selectedItem = 0;
int selectedPage = 0; int selectedPage = 0;
String selectedNode = ""; String selectedNode = "";
@ -31,20 +32,24 @@ MenuItem mainMenuItems[] = {
{"Manage VM", &manageVMMenu}, {"Manage VM", &manageVMMenu},
{"Manage Container", &manageContainerMenu}}; {"Manage Container", &manageContainerMenu}};
// Array of the VM managment menu items.
MenuItem manageVMItems[] = { MenuItem manageVMItems[] = {
{"Restart", &vmRestart}, {"Restart", &vmRestart},
{"Start", &vmStart}, {"Start", &vmStart},
{"Stop", &vmStop}, {"Stop", &vmStop},
}; };
// Array of the container management menu items.
MenuItem manageContainerItems[] = { MenuItem manageContainerItems[] = {
{"Restart", &containerRestart}, {"Restart", &containerRestart},
{"Start", &containerStart}, {"Start", &containerStart},
{"Stop", &containerStop}, {"Stop", &containerStop},
}; };
int buttonListener(int numItems) /// @brief Function to listen for button presses. Once called it will loop until a button is pressed. For the directional pad the selected page or item is changed and 0 is returned. For the A/B buttons 1/2 is returned to indicate that the user wants to select something or go back.
/// @param numItems A reference an integer which holds the number of items for the user to pick from in the menu.
/// @return An integer indicating what action was taken. 1 for the A button, 2 for the B button, 0 for any other input.
int buttonListener(const int &numItems)
{ {
delay(300); delay(300);
while (true) while (true)
@ -91,7 +96,15 @@ int buttonListener(int numItems)
return 0; return 0;
} }
void drawMenu(MenuItem menuItems[], int numItems, String menuTitle) /** @brief A function to draw a menu on the screen. This is for static menus which have a function tied to each item.
* Loops through the menu items and draws a ">" before the currently selected item.
* After printing the items, listens for button inputs. If the A button is pressed then the function of the currently selected item is run. If the B button is pressed the function stops running (returning the previous menu).
* If the directional pad buttons are pressed it means that the selected item or page has changed, so the function is run again to redraw the menu with the new values.
* @param menuItems An array of menuItems used to draw the menu.
* @param numItems A reference to an int which holds the number of items in the menu.
* @param menuTitle A reference to a string which holds the title of the menu.
**/
void drawMenu(MenuItem menuItems[], const int &numItems, const String &menuTitle)
{ {
GO.lcd.clearDisplay(); GO.lcd.clearDisplay();
GO.lcd.setCursor(0, 0); GO.lcd.setCursor(0, 0);
@ -105,6 +118,8 @@ void drawMenu(MenuItem menuItems[], int numItems, String menuTitle)
if (selectedItem == i) if (selectedItem == i)
{ {
GO.lcd.print("> "); GO.lcd.print("> ");
} else {
GO.lcd.print(" ");
} }
GO.lcd.println(menuItems[i].name); GO.lcd.println(menuItems[i].name);
} }
@ -124,6 +139,9 @@ void drawMenu(MenuItem menuItems[], int numItems, String menuTitle)
} }
} }
/**
* @brief Function to draw the main menu. Calls the draw menu function using the array of main menu items.
*/
void mainMenu() void mainMenu()
{ {
selectedItem = 0; selectedItem = 0;
@ -131,7 +149,9 @@ void mainMenu()
drawMenu(mainMenuItems, numItems, "Main Menu"); drawMenu(mainMenuItems, numItems, "Main Menu");
} }
/**
* @brief Function to draw the VM management menu. Calls the draw menu function using the array of VM mangement menu items.
*/
void manageVMMenu() void manageVMMenu()
{ {
selectedItem = 0; selectedItem = 0;
@ -140,6 +160,9 @@ void manageVMMenu()
mainMenu(); mainMenu();
} }
/**
* @brief Function to draw the container management menu. Calls the draw menu function using the array of container management menu items.
*/
void manageContainerMenu() void manageContainerMenu()
{ {
selectedItem = 0; selectedItem = 0;
@ -148,180 +171,146 @@ void manageContainerMenu()
mainMenu(); mainMenu();
} }
void listNodes(Node *nodes, int numItems) void containerMenuPrint(void *container)
{ {
GO.lcd.clearDisplay(); Container *cont = static_cast<Container *>(container);
GO.lcd.setTextColor(MAIN_TEXT_COLOR);
GO.lcd.setTextSize(MAIN_TEXT_SIZE);
GO.lcd.setCursor(0, 0);
GO.lcd.println("Select Node (Page " + String(selectedPage + 1) + ")");
GO.lcd.println("--------------------------");
for (int i = selectedPage * ITEMS_PER_PAGE; i < numItems && i < (selectedPage + 1) * ITEMS_PER_PAGE; i++) if ((*cont).onlineStatus == "running")
{ {
if (selectedItem == i) GO.lcd.setTextColor(ONLINE_COLOR);
{
GO.lcd.print("> ");
}
if (nodes[i].onlineStatus == "online") {
GO.lcd.setTextColor(ONLINE_COLOR);
} else {
GO.lcd.setTextColor(OFFLINE_COLOR);
}
GO.lcd.print("O");
GO.lcd.setTextColor(MAIN_TEXT_COLOR);
GO.lcd.println(nodes[i].name);
} }
switch (buttonListener(numItems)) else
{ {
case 1: GO.lcd.setTextColor(OFFLINE_COLOR);
Serial.println("selected " + selectedItem);
selectedNode = nodes[selectedItem].name;
break;
default:
listNodes(nodes, numItems);
break;
} }
} GO.lcd.print("O ");
GO.lcd.setTextColor(MAIN_TEXT_COLOR);
GO.lcd.println(String((*cont).id) + ": " + (*cont).name);
};
void listContainers(Container *containers, int numItems) void vmMenuPrint(void *vm)
{ {
GO.lcd.clearDisplay(); VM *v = static_cast<VM *>(vm);
GO.lcd.setCursor(0, 0);
GO.lcd.setTextColor(MAIN_TEXT_COLOR);
GO.lcd.setTextSize(MAIN_TEXT_SIZE);
GO.lcd.println("Select Container (Page " + String(selectedPage + 1) + ")");
GO.lcd.println("--------------------------");
for (int i = selectedPage * ITEMS_PER_PAGE; i < numItems && i < (selectedPage + 1) * ITEMS_PER_PAGE; i++) if ((*v).onlineStatus == "running")
{ {
if (selectedItem == i) GO.lcd.setTextColor(ONLINE_COLOR);
{
GO.lcd.print("> ");
}
if (containers[i].onlineStatus == "running") {
GO.lcd.setTextColor(ONLINE_COLOR);
} else {
GO.lcd.setTextColor(OFFLINE_COLOR);
}
GO.lcd.print("O");
GO.lcd.setTextColor(MAIN_TEXT_COLOR);
GO.lcd.println(String(containers[i].id) + ": " + containers[i].name);
} }
else
switch (buttonListener(numItems))
{ {
case 1: GO.lcd.setTextColor(OFFLINE_COLOR);
selectedLXC = containers[selectedItem].id;
break;
case 2:
Serial.println("back");
break;
default:
listContainers(containers, numItems);
break;
} }
} GO.lcd.print("O ");
GO.lcd.setTextColor(MAIN_TEXT_COLOR);
GO.lcd.println(String((*v).id) + ": " + (*v).name);
};
void listVMs(VM *vms, int numItems) void nodeMenuPrint(void *node)
{ {
GO.lcd.clearDisplay(); Node *n = static_cast<Node *>(node);
GO.lcd.setCursor(0, 0);
GO.lcd.setTextColor(MAIN_TEXT_COLOR);
GO.lcd.setTextSize(MAIN_TEXT_SIZE);
GO.lcd.println("Select VM (Page " + String(selectedPage + 1) + ")");
GO.lcd.println("--------------------------");
for (int i = selectedPage * ITEMS_PER_PAGE; i < numItems && i < (selectedPage + 1) * ITEMS_PER_PAGE; i++) if ((*n).onlineStatus == "online")
{ {
if (selectedItem == i) GO.lcd.setTextColor(ONLINE_COLOR);
{
GO.lcd.print("> ");
}
if (vms[i].onlineStatus == "running") {
GO.lcd.setTextColor(ONLINE_COLOR);
} else {
GO.lcd.setTextColor(OFFLINE_COLOR);
}
GO.lcd.print("O");
GO.lcd.setTextColor(MAIN_TEXT_COLOR);
GO.lcd.println(String(vms[i].id) + ": " + vms[i].name);
} }
else
switch (buttonListener(numItems))
{ {
case 1: GO.lcd.setTextColor(OFFLINE_COLOR);
selectedVM = vms[selectedItem].id;
break;
case 2:
Serial.println("back");
break;
default:
listVMs(vms, numItems);
break;
} }
GO.lcd.print("O ");
GO.lcd.setTextColor(MAIN_TEXT_COLOR);
GO.lcd.println((*n).name);
}
void diskMenuPrint(void *disk)
{
Disk *d = static_cast<Disk *>(disk);
GO.lcd.println((*d).devpath);
} }
void listDisks(Disk *disks, int numItems) void poolMenuPrint(void *pool)
{
Pool *p = static_cast<Pool *>(pool);
GO.lcd.println((*p).name);
}
void listItems(void *items, void **item, const String title, const int &numItems, const int &itemSize, const bool &backEnabled, MenuPrintCallback printMachine)
{ {
GO.lcd.clearDisplay(); GO.lcd.clearDisplay();
GO.lcd.setCursor(0, 0); GO.lcd.setCursor(0, 0);
GO.lcd.setTextColor(MAIN_TEXT_COLOR); GO.lcd.setTextColor(MAIN_TEXT_COLOR);
GO.lcd.setTextSize(MAIN_TEXT_SIZE); GO.lcd.setTextSize(MAIN_TEXT_SIZE);
GO.lcd.println("Select Disk (Page " + String(selectedPage + 1) + ")"); GO.lcd.println(title + " (Page " + String(selectedPage + 1) + ")");
GO.lcd.println("--------------------------"); GO.lcd.println("--------------------------");
// Cast items to char for pointer calculation
char *itemsAsBytes = static_cast<char *>(items);
for (int i = selectedPage * ITEMS_PER_PAGE; i < numItems && i < (selectedPage + 1) * ITEMS_PER_PAGE; i++) for (int i = selectedPage * ITEMS_PER_PAGE; i < numItems && i < (selectedPage + 1) * ITEMS_PER_PAGE; i++)
{ {
if (selectedItem == i) if (selectedItem == i)
{ {
GO.lcd.print("> "); GO.lcd.print("> ");
} else {
GO.lcd.print(" ");
} }
GO.lcd.println(disks[i].devpath); printMachine(itemsAsBytes + i * itemSize);
} }
switch (buttonListener(numItems)) switch (buttonListener(numItems))
{ {
case 1: case 1:
selectedDisk = disks[selectedItem].devpath; *item = itemsAsBytes + selectedItem * itemSize;
break; break;
case 2: case 2:
Serial.println("back"); if (backEnabled)
break; {
Serial.println("back");
break;
}
default: default:
listDisks(disks, numItems); listItems(items, item, title, numItems, itemSize, backEnabled, printMachine);
break; break;
} }
} }
void listPools(Pool *pools, int numItems) void listNodes(Node *nodes, const int &numItems)
{ {
GO.lcd.clearDisplay(); void *item;
GO.lcd.setCursor(0, 0); listItems(nodes, &item, "Select Node", numItems, sizeof(Node), false, nodeMenuPrint);
GO.lcd.setTextColor(MAIN_TEXT_COLOR); Node *node = static_cast<Node *>(item);
GO.lcd.setTextSize(MAIN_TEXT_SIZE); Serial.println((*node).name);
GO.lcd.println("Select Pool (Page " + String(selectedPage + 1) + ")"); selectedNode = (*node).name;
GO.lcd.println("--------------------------"); }
for (int i = selectedPage * ITEMS_PER_PAGE; i < numItems && i < (selectedPage + 1) * ITEMS_PER_PAGE; i++) void listContainers(Container *containers, const int &numItems)
{ {
if (selectedItem == i) void *item;
{ listItems(containers, &item, "Select Container", numItems, sizeof(Container), true, containerMenuPrint);
GO.lcd.print("> "); Container *container = static_cast<Container *>(item);
} selectedLXC = (*container).id;
GO.lcd.println(pools[i].name); }
}
switch (buttonListener(numItems)) void listVMs(VM *vms, const int &numItems)
{ {
case 1: void *item;
selectedPool = pools[selectedItem].name; listItems(vms, &item, "Select VM", numItems, sizeof(VM), true, vmMenuPrint);
break; VM *vm = static_cast<VM *>(item);
case 2: selectedVM = (*vm).id;
Serial.println("back"); }
break;
default: void listDisks(Disk *disks, const int &numItems)
listPools(pools, numItems); {
break; void *item;
} listItems(disks, &item, "Select Disk", numItems, sizeof(Disk), true, diskMenuPrint);
} Disk *disk = static_cast<Disk *>(item);
selectedDisk = (*disk).devpath;
}
void listPools(Pool *pools, const int &numItems)
{
void *item;
listItems(pools, &item, "Select Pool", numItems, sizeof(Pool), true, poolMenuPrint);
Pool *pool = static_cast<Pool *>(item);
selectedPool = (*pool).name;
}

@ -9,7 +9,7 @@ const int BACKGROUND_COLOR = WHITE;
const int TEXT_COLOR = BLACK; const int TEXT_COLOR = BLACK;
const int TEXT_SIZE = 2; const int TEXT_SIZE = 2;
String convertBytes(long long value) String convertBytes(const long long &value)
{ {
if (value > 1099511627776) if (value > 1099511627776)
{ {
@ -30,7 +30,7 @@ String convertBytes(long long value)
return String(value) + " Bytes"; return String(value) + " Bytes";
} }
String convertTime(long long value) String convertTime(const long long &value)
{ {
if (value > 3600) if (value > 3600)
{ {
@ -43,7 +43,7 @@ String convertTime(long long value)
return String(value) + " secs"; return String(value) + " secs";
} }
void printNodeStats(Node node) void printNodeStats(const Node &node)
{ {
GO.lcd.fillScreen(BACKGROUND_COLOR); GO.lcd.fillScreen(BACKGROUND_COLOR);
GO.lcd.setCursor(0, 0); GO.lcd.setCursor(0, 0);
@ -63,7 +63,7 @@ void printNodeStats(Node node)
GO.lcd.println("Max Disk: " + convertBytes(node.maxdisk)); GO.lcd.println("Max Disk: " + convertBytes(node.maxdisk));
} }
void printContainerStats(Container container) void printContainerStats(const Container &container)
{ {
GO.lcd.fillScreen(BACKGROUND_COLOR); GO.lcd.fillScreen(BACKGROUND_COLOR);
@ -79,7 +79,7 @@ void printContainerStats(Container container)
GO.lcd.println("Max Disk: " + convertBytes(container.maxdisk)); GO.lcd.println("Max Disk: " + convertBytes(container.maxdisk));
} }
void printVMStats(VM vm) void printVMStats(const VM &vm)
{ {
GO.lcd.fillScreen(BACKGROUND_COLOR); GO.lcd.fillScreen(BACKGROUND_COLOR);
@ -94,7 +94,7 @@ void printVMStats(VM vm)
GO.lcd.println("Max Disk: " + convertBytes(vm.maxdisk)); GO.lcd.println("Max Disk: " + convertBytes(vm.maxdisk));
} }
void printDiskStats(Disk disk) void printDiskStats(const Disk &disk)
{ {
GO.lcd.fillScreen(BACKGROUND_COLOR); GO.lcd.fillScreen(BACKGROUND_COLOR);
@ -112,7 +112,7 @@ void printDiskStats(Disk disk)
GO.lcd.println("Health: " + disk.health); GO.lcd.println("Health: " + disk.health);
} }
void printPoolStats(Pool pool) void printPoolStats(const Pool &pool)
{ {
GO.lcd.fillScreen(BACKGROUND_COLOR); GO.lcd.fillScreen(BACKGROUND_COLOR);
@ -156,7 +156,7 @@ void containerInfo()
selectedPage = 0; selectedPage = 0;
int numContainers; int numContainers;
Container *containers = getContainerInfo(&numContainers, selectedNode); Container *containers = getContainerInfo(numContainers, selectedNode);
listContainers(containers, numContainers); listContainers(containers, numContainers);
delete[] containers; delete[] containers;
@ -186,7 +186,7 @@ void vmInfo()
selectedItem = 0; selectedItem = 0;
selectedPage = 0; selectedPage = 0;
int numVMs; int numVMs;
VM *vms = getVMInfo(&numVMs, selectedNode); VM *vms = getVMInfo(numVMs, selectedNode);
listVMs(vms, numVMs); listVMs(vms, numVMs);
delete[] vms; delete[] vms;
unsigned long lastUpdate = millis(); unsigned long lastUpdate = millis();
@ -213,7 +213,7 @@ void diskInfo()
selectedItem = 0; selectedItem = 0;
selectedPage = 0; selectedPage = 0;
int numDisks; int numDisks;
Disk *disks = getDiskInfo(&numDisks, selectedNode); Disk *disks = getDiskInfo(numDisks, selectedNode);
listDisks(disks, numDisks); listDisks(disks, numDisks);
delete[] disks; delete[] disks;
@ -236,7 +236,7 @@ void poolInfo()
selectedItem = 0; selectedItem = 0;
selectedPage = 0; selectedPage = 0;
int numPools; int numPools;
Pool *pools = getPoolInfo(&numPools, selectedNode); Pool *pools = getPoolInfo(numPools, selectedNode);
listPools(pools, numPools); listPools(pools, numPools);
delete[] pools; delete[] pools;

Loading…
Cancel
Save