Adding LXD tables (#6249)

Co-authored-by: Stefano Bonicatti <stefano.bonicatti@gmail.com>
This commit is contained in:
scoders-tob 2020-03-15 21:02:18 -04:00 committed by GitHub
parent aeaf6249ce
commit 4e5dcd9832
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 865 additions and 0 deletions

View File

@ -25,6 +25,7 @@ function(generateOsqueryTablesApplications)
posix/browser_opera.cpp
posix/carbon_black.cpp
posix/docker.cpp
posix/lxd.cpp
posix/prometheus_metrics.cpp
)
endif()

View File

@ -0,0 +1,704 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed in accordance with the terms specified in
* the LICENSE file found in the root directory of this source tree.
*/
#include <regex>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/asio.hpp>
#include <boost/foreach.hpp>
#if !defined(BOOST_ASIO_HAS_LOCAL_SOCKETS)
#error Boost error: Local sockets not available
#endif
#include <osquery/flags.h>
#include <osquery/logger.h>
#include <osquery/tables.h>
namespace pt = boost::property_tree;
namespace local = boost::asio::local;
using pt_path = pt::ptree::path_type;
namespace osquery {
/**
* @brief LXD UNIX domain socket path.
* Usual suspects: /var/lib/lxd/unix.socket,
* /var/snap/lxd/common/lxd/unix.socket
* If using a different path, specify that path.
*/
FLAG(string,
lxd_socket,
"/var/lib/lxd/unix.socket",
"LXD UNIX domain socket path");
namespace tables {
/**
* @brief Makes API calls to the LXD UNIX socket.
*
* @param uri Relative URI to invoke GET HTTP method.
* @param tree Property tree where JSON result is stored.
* @return Status with 0 code on success. Non-negative status with error
* message.
*/
Status lxdApi(const std::string& uri, pt::ptree& tree) {
static const std::regex httpOkRegex("HTTP/1\\.(0|1) 20(0|2) OK\\\r");
try {
local::stream_protocol::endpoint ep(FLAGS_lxd_socket);
local::stream_protocol::iostream stream(ep);
if (!stream) {
return Status::failure("Error connecting to LXD sock: " +
stream.error().message());
}
stream << "GET " << uri
<< " HTTP/1.0\r\nAccept: */*\r\nConnection: close\r\n\r\n"
<< std::flush;
if (stream.eof()) {
stream.close();
return Status::failure("Empty LXD API response for: " + uri);
}
std::string str;
getline(stream, str);
std::smatch match;
if (!std::regex_match(str, match, httpOkRegex)) {
stream.close();
return Status::failure("Invalid LXD API response for " + uri + ": " +
str);
}
// Skip empty line between header and body
while (!stream.eof() && str != "\r") {
getline(stream, str);
}
try {
pt::read_json(stream, tree);
} catch (const pt::ptree_error& e) {
stream.close();
return Status::failure("Error reading LXD API response for " + uri +
": " + e.what());
}
stream.close();
} catch (const std::exception& e) {
return Status::failure(std::string("Error calling LXD API: ") + e.what());
}
return Status::success();
}
/**
* @brief Get per-instance state
*/
void getLxdInstanceState(const std::string& url, Row& row) {
pt::ptree tree;
Status s = lxdApi(url + "/state", tree);
if (!s.ok()) {
VLOG(1) << "Error getting LXD instance state" << url << ": " << s.what();
return;
}
try {
const pt::ptree& node = tree.get_child("metadata");
row["pid"] = INTEGER(node.get<int>("pid"));
row["processes"] = INTEGER(node.get<int>("processes"));
} catch (const pt::ptree_error& e) {
VLOG(1) << "Error parsing details for LXD instance state " << url << ": "
<< e.what();
}
}
/**
* @brief Get per-instance metadata
*/
void getLxdInstanceMetadata(const std::string& url, Row& row) {
pt::ptree tree;
Status s = lxdApi(url + "/metadata", tree);
if (!s.ok()) {
VLOG(1) << "Error getting LXD instance metadata" << url << ": " << s.what();
return;
}
try {
const pt::ptree& node = tree.get_child("metadata").get_child("properties");
row["description"] = node.get<std::string>("description");
row["os"] = node.get<std::string>("os");
row["architecture"] = node.get<std::string>("architecture");
} catch (const pt::ptree_error& e) {
VLOG(1) << "Error parsing details for LXD instance metadata " << url << ": "
<< e.what();
}
}
/**
* @brief Get per-instance info
*/
void getLxdInstance(const std::string& url, QueryData& results) {
pt::ptree tree;
Status s = lxdApi(url, tree);
if (!s.ok()) {
VLOG(1) << "Error querying LXD instance " << url << ": " << s.what();
return;
}
try {
const pt::ptree& node = tree.get_child("metadata");
Row r;
r["name"] = node.get<std::string>("name");
r["status"] = node.get<std::string>("status");
r["stateful"] = node.get<bool>("stateful") ? INTEGER(1) : INTEGER(0);
r["ephemeral"] = node.get<bool>("ephemeral") ? INTEGER(1) : INTEGER(0);
r["created_at"] = node.get<std::string>("created_at");
r["base_image"] = node.get_child("config").get<std::string>(
pt_path("volatile.base_image", '/'));
getLxdInstanceMetadata(url, r);
getLxdInstanceState(url, r);
results.push_back(r);
} catch (const pt::ptree_error& e) {
VLOG(1) << "Error parsing details for instance " << url << ": " << e.what();
}
}
/**
* @brief Calls getLxdInstance() for all LXD instances
*/
void getLxdInstances(QueryData& results) {
pt::ptree tree;
Status s = lxdApi("/1.0/containers", tree);
if (!s.ok()) {
VLOG(1) << "Error getting LXD instances: " << s.what();
return;
}
for (const auto& node : tree.get_child("metadata")) {
std::string instance_url = node.second.data();
getLxdInstance(instance_url, results);
}
}
/**
* @brief Entry point for lxd_instances table.
*/
QueryData genLxdInstances(QueryContext& context) {
QueryData results;
if (context.constraints["name"].exists(EQUALS)) {
for (const auto& name : context.constraints["name"].getAll(EQUALS)) {
std::string url = "/1.0/containers/" + name;
// using /containers instead of /instances for backward compatibility
getLxdInstance(url, results);
}
} else {
getLxdInstances(results);
}
return results;
}
/**
* @brief Get per-instance config info
*/
void getLxdInstanceConfig(const std::string& name, QueryData& results) {
pt::ptree tree;
Status s = lxdApi("/1.0/containers/" + name, tree);
if (!s.ok()) {
VLOG(1) << "Error getting LXD instance " << name << ": " << s.what();
return;
}
try {
for (const auto& node : tree.get_child("metadata").get_child("config")) {
Row r;
r["name"] = name;
r["key"] = node.first;
r["value"] = node.second.data();
results.push_back(r);
}
} catch (const pt::ptree_error& e) {
VLOG(1) << "Error parsing details for LXD instance " << name << ": "
<< e.what();
}
}
/**
* @brief Entry point for lxd_instance_config table.
*/
QueryData genLxdInstanceConfig(QueryContext& context) {
QueryData results;
for (const auto& name : context.constraints["name"].getAll(EQUALS)) {
getLxdInstanceConfig(name, results);
}
return results;
}
/**
* @brief Get per-instance device info
*/
void getLxdInstanceDevice(const std::string& dev_name,
const pt::ptree& dev_node,
const std::string& instance_name,
QueryData& results) {
try {
for (const auto& dev_info : dev_node) {
if (dev_info.first == "type") {
continue;
}
Row r;
r["name"] = instance_name;
r["device"] = dev_name;
r["device_type"] = dev_node.get<std::string>("type", "");
r["key"] = dev_info.first;
r["value"] = dev_info.second.data();
results.push_back(r);
}
} catch (const pt::ptree_error& e) {
VLOG(1) << "Error parsing device details for LXD instance " << instance_name
<< ": " << e.what();
}
}
/**
* @brief Get per-instance devices info
*/
void getLxdInstanceDevices(const std::string& name, QueryData& results) {
pt::ptree tree;
Status s = lxdApi("/1.0/containers/" + name, tree);
if (!s.ok()) {
VLOG(1) << "Error getting LXD instance " << name << ": " << s.what();
return;
}
try {
for (const auto& node :
tree.get_child("metadata").get_child("expanded_devices")) {
getLxdInstanceDevice(node.first, node.second, name, results);
}
} catch (const pt::ptree_error& e) {
VLOG(1) << "Error parsing details for LXD instance " << name << ": "
<< e.what();
}
}
/**
* @brief Entry point for lxd_instance_devices table.
*/
QueryData genLxdInstanceDevices(QueryContext& context) {
QueryData results;
for (const auto& name : context.constraints["name"].getAll(EQUALS)) {
getLxdInstanceDevices(name, results);
}
return results;
}
/**
* @brief Get per-image info
*/
void getImage(const std::string& url,
const std::string& id,
QueryData& results) {
pt::ptree tree;
Status s = lxdApi(url, tree);
if (!s.ok()) {
VLOG(1) << "Error querying LXD image " << url << ": " << s.what();
return;
}
try {
const pt::ptree& node = tree.get_child("metadata");
Row r;
r["id"] = id.empty() ? node.get<std::string>("fingerprint") : id;
r["architecture"] = node.get<std::string>("architecture");
r["os"] = node.get_child("properties").get<std::string>("os");
r["release"] = node.get_child("properties").get<std::string>("release");
r["description"] =
node.get_child("properties").get<std::string>("description");
r["filename"] = node.get<std::string>("filename");
r["size"] = BIGINT(node.get<uint64_t>("size"));
r["auto_update"] = node.get<bool>("auto_update") ? INTEGER(1) : INTEGER(0);
r["cached"] = node.get<bool>("cached") ? INTEGER(1) : INTEGER(0);
r["public"] = node.get<bool>("public") ? INTEGER(1) : INTEGER(0);
r["created_at"] = node.get<std::string>("created_at");
r["expires_at"] = node.get<std::string>("expires_at");
r["uploaded_at"] = node.get<std::string>("uploaded_at");
r["last_used_at"] = node.get<std::string>("last_used_at");
r["update_source_server"] =
node.get_child("update_source").get<std::string>("server");
r["update_source_protocol"] =
node.get_child("update_source").get<std::string>("protocol");
r["update_source_certificate"] =
node.get_child("update_source").get<std::string>("certificate");
r["update_source_alias"] =
node.get_child("update_source").get<std::string>("alias");
std::string aliases;
for (const auto& alias : node.get_child("aliases")) {
if (!aliases.empty()) {
aliases.append(",");
}
aliases.append(alias.second.get<std::string>("name"));
}
r["aliases"] = aliases;
results.push_back(r);
} catch (const pt::ptree_error& e) {
VLOG(1) << "Error parsing details for image " << url << ": " << e.what();
}
}
/**
* @brief Calls getImage() for all LXD images
*/
void getImages(QueryData& results) {
pt::ptree tree;
Status s = lxdApi("/1.0/images", tree);
if (!s.ok()) {
VLOG(1) << "Error getting LXD images: " << s.what();
return;
}
for (const auto& node : tree.get_child("metadata")) {
std::string image_url = node.second.data();
getImage(image_url, std::string(), results);
}
}
/**
* @brief Entry point for lxd_images table.
*/
QueryData genLxdImages(QueryContext& context) {
QueryData results;
if (context.constraints["id"].exists(EQUALS)) {
for (const auto& id : context.constraints["id"].getAll(EQUALS)) {
std::string url = "/1.0/images/" + id;
getImage(url, id, results);
}
} else {
getImages(results);
}
return results;
}
/**
* @brief Get per-certificate info
*/
void getLxdCert(const std::string& url, QueryData& results) {
pt::ptree tree;
Status s = lxdApi(url, tree);
if (!s.ok()) {
VLOG(1) << "Error getting LXD certificate " << url << ": " << s.what();
return;
}
try {
const pt::ptree& node = tree.get_child("metadata");
Row r;
r["name"] = node.get<std::string>("name", "");
r["type"] = node.get<std::string>("type", "");
r["fingerprint"] = node.get<std::string>("fingerprint", "");
r["certificate"] = node.get<std::string>("certificate", "");
results.push_back(r);
} catch (const pt::ptree_error& e) {
VLOG(1) << "Error parsing details for certificate " << url << ": "
<< e.what();
}
}
/**
* @brief Entry point for lxd_certificates table.
*/
QueryData genLxdCerts(QueryContext& context) {
QueryData results;
pt::ptree tree;
Status s = lxdApi("/1.0/certificates", tree);
if (!s.ok()) {
VLOG(1) << "Error getting LXD certificates: " << s.what();
return results;
}
for (const auto& node : tree.get_child("metadata")) {
std::string cert_url = node.second.data();
getLxdCert(cert_url, results);
}
return results;
}
/**
* @brief Get per-network info additional
*/
void getLxdNetworkState(const std::string& url, Row& row) {
pt::ptree tree;
Status s = lxdApi(url + "/state", tree);
if (!s.ok()) {
VLOG(1) << "Error getting LXD network state" << url << ": " << s.what();
return;
}
try {
const pt::ptree& node = tree.get_child("metadata");
const pt::ptree& counter_node = node.get_child("counters");
row["bytes_received"] =
BIGINT(counter_node.get<uint64_t>("bytes_received"));
row["bytes_sent"] = BIGINT(counter_node.get<uint64_t>("bytes_sent"));
row["packets_received"] =
BIGINT(counter_node.get<uint64_t>("packets_received"));
row["packets_sent"] = BIGINT(counter_node.get<uint64_t>("packets_sent"));
row["hwaddr"] = node.get<std::string>("hwaddr");
row["state"] = node.get<std::string>("state");
row["mtu"] = INTEGER(node.get<int>("mtu"));
} catch (const pt::ptree_error& e) {
VLOG(1) << "Error parsing details for network state " << url << ": "
<< e.what();
}
}
/**
* @brief Get network user info
*/
void getLxdNetworkUsers(const pt::ptree& users_node, Row& row) {
try {
std::string users;
for (const auto& node : users_node) {
if (!users.empty()) {
users.append(",");
}
std::string user = node.second.data();
if (boost::starts_with(user, "/1.0/containers/")) {
user.erase(0, 16);
} else if (boost::starts_with(user, "/1.0/instances/")) {
user.erase(0, 15);
}
users.append(user);
}
row["used_by"] = users;
} catch (const pt::ptree_error& e) {
VLOG(1) << "Error getting network user details: " << e.what();
}
}
/**
* @brief Get per-network info
*/
void getLxdNetwork(const std::string& url, QueryData& results) {
pt::ptree tree;
Status s = lxdApi(url, tree);
if (!s.ok()) {
VLOG(1) << "Error getting LXD network " << url << ": " << s.what();
return;
}
try {
const pt::ptree& node = tree.get_child("metadata");
const pt::ptree& config_node = node.get_child("config");
Row r;
r["name"] = node.get<std::string>("name");
r["type"] = node.get<std::string>("type");
r["managed"] = node.get<bool>("managed") ? INTEGER(1) : INTEGER(0);
r["ipv4_address"] =
config_node.get<std::string>(pt_path("ipv4.address", '/'), "");
r["ipv6_address"] =
config_node.get<std::string>(pt_path("ipv6.address", '/'), "");
getLxdNetworkUsers(node.get_child("used_by"), r);
getLxdNetworkState(url, r);
results.push_back(r);
} catch (const pt::ptree_error& e) {
VLOG(1) << "Error parsing details for network " << url << ": " << e.what();
}
}
/**
* @brief Entry point for lxd_networks table.
*/
QueryData genLxdNetworks(QueryContext& context) {
QueryData results;
pt::ptree tree;
Status s = lxdApi("/1.0/networks", tree);
if (!s.ok()) {
VLOG(1) << "Error getting LXD networks: " << s.what();
return results;
}
for (const auto& node : tree.get_child("metadata")) {
std::string nw_url = node.second.data();
getLxdNetwork(nw_url, results);
}
return results;
}
/**
* @brief Entry point for lxd_cluster table.
*/
QueryData genLxdCluster(QueryContext& context) {
QueryData results;
pt::ptree tree;
Status s = lxdApi("/1.0/cluster", tree);
if (!s.ok()) {
VLOG(1) << "Error getting LXD cluster: " << s.what();
return results;
}
try {
const auto& node = tree.get_child("metadata");
Row r;
r["server_name"] = node.get<std::string>("server_name");
r["enabled"] = node.get<bool>("enabled") ? INTEGER(1) : INTEGER(0);
for (const auto& member_node : node.get_child("member_config")) {
r["member_config_entity"] = member_node.second.get<std::string>("entity");
r["member_config_name"] = member_node.second.get<std::string>("name");
r["member_config_key"] = member_node.second.get<std::string>("key");
r["member_config_value"] =
member_node.second.get<std::string>("value", "");
r["member_config_description"] =
member_node.second.get<std::string>("description");
}
results.push_back(r);
} catch (const pt::ptree_error& e) {
VLOG(1) << "Error parsing details for LXD cluster: " << e.what();
}
return results;
}
/**
* @brief Get per-cluster-member info
*/
void getLxdClusterMember(const std::string& url, QueryData& results) {
pt::ptree tree;
Status s = lxdApi(url, tree);
if (!s.ok()) {
VLOG(1) << "Error getting LXD cluster member " << url << ": " << s.what();
return;
}
try {
const pt::ptree& node = tree.get_child("metadata");
Row r;
r["server_name"] = node.get<std::string>("server_name");
r["url"] = node.get<std::string>("url");
r["database"] = node.get<bool>("database") ? INTEGER(1) : INTEGER(0);
r["status"] = node.get<std::string>("status");
r["message"] = node.get<std::string>("message");
results.push_back(r);
} catch (const pt::ptree_error& e) {
VLOG(1) << "Error parsing details for cluster member " << url << ": "
<< e.what();
}
}
/**
* @brief Entry point for lxd_cluster_members table.
*/
QueryData genLxdClusterMembers(QueryContext& context) {
QueryData results;
pt::ptree tree;
Status s = lxdApi("/1.0/cluster/members", tree);
if (!s.ok()) {
VLOG(1) << "Error getting LXD cluster members: " << s.what();
return results;
}
for (const auto& node : tree.get_child("metadata")) {
std::string url = node.second.data();
getLxdClusterMember(url, results);
}
return results;
}
/**
* @brief Get per-storage-pool resources
*/
void getLxdStoragePoolResources(const std::string& url, Row& row) {
pt::ptree tree;
Status s = lxdApi(url + "/resources", tree);
if (!s.ok()) {
VLOG(1) << "Error getting LXD storage pool resources" << url << ": "
<< s.what();
return;
}
try {
const pt::ptree& node = tree.get_child("metadata");
row["space_used"] = BIGINT(node.get_child("space").get<uint64_t>("used"));
row["space_total"] = BIGINT(node.get_child("space").get<uint64_t>("total"));
row["inodes_used"] = BIGINT(node.get_child("inodes").get<uint64_t>("used"));
row["inodes_total"] =
BIGINT(node.get_child("inodes").get<uint64_t>("total"));
} catch (const pt::ptree_error& e) {
VLOG(1) << "Error parsing details for storage pool resources " << url
<< ": " << e.what();
}
}
/**
* @brief Get per-storage-pool info
*/
void getLxdStoragePool(const std::string& url, QueryData& results) {
pt::ptree tree;
Status s = lxdApi(url, tree);
if (!s.ok()) {
VLOG(1) << "Error getting LXD storage pool " << url << ": " << s.what();
return;
}
try {
const pt::ptree& node = tree.get_child("metadata");
const pt::ptree& config_node = node.get_child("config");
Row r;
r["name"] = node.get<std::string>("name");
r["driver"] = node.get<std::string>("driver");
r["source"] = config_node.get<std::string>("source", "");
r["size"] = config_node.get<std::string>("size", "");
getLxdStoragePoolResources(url, r);
results.push_back(r);
} catch (const pt::ptree_error& e) {
VLOG(1) << "Error parsing details for storage pool " << url << ": "
<< e.what();
}
}
/**
* @brief Entry point for lxd_storage_pools table.
*/
QueryData genLxdStoragePools(QueryContext& context) {
QueryData results;
pt::ptree tree;
Status s = lxdApi("/1.0/storage-pools", tree);
if (!s.ok()) {
VLOG(1) << "Error getting LXD storage pools: " << s.what();
return results;
}
for (const auto& node : tree.get_child("metadata")) {
std::string url = node.second.data();
getLxdStoragePool(url, results);
}
return results;
}
} // namespace tables
} // namespace osquery

View File

@ -206,6 +206,15 @@ function(generateNativeTables)
"posix/known_hosts.table:linux,macos,freebsd"
"posix/last.table:linux,macos,freebsd"
"posix/load_average.table:linux,macos,freebsd"
"posix/lxd_instances.table:linux"
"posix/lxd_instance_config.table:linux"
"posix/lxd_instance_devices.table:linux"
"posix/lxd_cluster.table:linux"
"posix/lxd_cluster_members.table:linux"
"posix/lxd_images.table:linux"
"posix/lxd_certificates.table:linux"
"posix/lxd_networks.table:linux"
"posix/lxd_storage_pools.table:linux"
"posix/magic.table:linux,macos,freebsd"
"posix/memory_array_mapped_addresses.table:linux,macos"
"posix/memory_arrays.table:linux,macos"

View File

@ -0,0 +1,12 @@
table_name("lxd_certificates")
description("LXD certificates information.")
schema([
Column("name", TEXT, "Name of the certificate"),
Column("type", TEXT, "Type of the certificate"),
Column("fingerprint", TEXT, "SHA256 hash of the certificate"),
Column("certificate", TEXT, "Certificate content")
])
implementation("applications/lxd@genLxdCerts")
examples([
"select * from lxd_certificates"
])

View File

@ -0,0 +1,15 @@
table_name("lxd_cluster")
description("LXD cluster information.")
schema([
Column("server_name", TEXT, "Name of the LXD server node"),
Column("enabled", INTEGER, "Whether clustering enabled (1) or not (0) on this node"),
Column("member_config_entity", TEXT, "Type of configuration parameter for this node"),
Column("member_config_name", TEXT, "Name of configuration parameter"),
Column("member_config_key", TEXT, "Config key"),
Column("member_config_value", TEXT, "Config value"),
Column("member_config_description", TEXT, "Config description")
])
implementation("applications/lxd@genLxdCluster")
examples([
"select * from lxd_cluster"
])

View File

@ -0,0 +1,13 @@
table_name("lxd_cluster_members")
description("LXD cluster members information.")
schema([
Column("server_name", TEXT, "Name of the LXD server node"),
Column("url", TEXT, "URL of the node"),
Column("database", INTEGER, "Whether the server is a database node (1) or not (0)"),
Column("status", TEXT, "Status of the node (Online/Offline)"),
Column("message", TEXT, "Message from the node (Online/Offline)")
])
implementation("applications/lxd@genLxdClusterMembers")
examples([
"select * from lxd_cluster_members"
])

View File

@ -0,0 +1,29 @@
table_name("lxd_images")
description("LXD images information.")
schema([
Column("id", TEXT, "Image ID", index=True),
Column("architecture", TEXT, "Target architecture for the image"),
Column("os", TEXT, "OS on which image is based"),
Column("release", TEXT, "OS release version on which the image is based"),
Column("description", TEXT, "Image description"),
Column("aliases", TEXT, "Comma-separated list of image aliases"),
Column("filename", TEXT, "Filename of the image file"),
Column("size", BIGINT, "Size of image in bytes"),
Column("auto_update", INTEGER, "Whether the image auto-updates (1) or not (0)"),
Column("cached", INTEGER, "Whether image is cached (1) or not (0)"),
Column("public", INTEGER, "Whether image is public (1) or not (0)"),
Column("created_at", TEXT, "ISO time of image creation"),
Column("expires_at", TEXT, "ISO time of image expiration"),
Column("uploaded_at", TEXT, "ISO time of image upload"),
Column("last_used_at", TEXT, "ISO time for the most recent use of this image in terms of container spawn"),
Column("update_source_server", TEXT, "Server for image update"),
Column("update_source_protocol", TEXT, "Protocol used for image information update and image import from source server"),
Column("update_source_certificate", TEXT, "Certificate for update source server"),
Column("update_source_alias", TEXT, "Alias of image at update source server")
])
implementation("applications/lxd@genLxdImages")
examples([
"select * from lxd_images",
"select * from lxd_images where id = '0931b693c8'",
"select * from lxd_images where id = '0931b693c877ef357b9e17b3195ae952a2450873923ffd2b34b60836ea730cfa'",
])

View File

@ -0,0 +1,11 @@
table_name("lxd_instance_config")
description("LXD instance configuration information.")
schema([
Column("name", TEXT, "Instance name", index=True, required=True),
Column("key", TEXT, "Configuration parameter name"),
Column("value", TEXT, "Configuration parameter value")
])
implementation("applications/lxd@genLxdInstanceConfig")
examples([
"select * from lxd_instance_config where name = 'hello'"
])

View File

@ -0,0 +1,14 @@
table_name("lxd_instance_devices")
description("LXD instance devices information.")
schema([
Column("name", TEXT, "Instance name", index=True, required=True),
Column("device", TEXT, "Name of the device"),
Column("device_type", TEXT, "Device type"),
Column("key", TEXT, "Device info param name"),
Column("value", TEXT, "Device info param value")
])
implementation("applications/lxd@genLxdInstanceDevices")
examples([
"select * from lxd_instance_devices where name = 'hello'"
])

View File

@ -0,0 +1,20 @@
table_name("lxd_instances")
description("LXD instances information.")
schema([
Column("name", TEXT, "Instance name", index=True),
Column("status", TEXT, "Instance state (running, stopped, etc.)"),
Column("stateful", INTEGER, "Whether the instance is stateful(1) or not(0)"),
Column("ephemeral", INTEGER, "Whether the instance is ephemeral(1) or not(0)"),
Column("created_at", TEXT, "ISO time of creation"),
Column("base_image", TEXT, "ID of image used to launch this instance"),
Column("architecture", TEXT, "Instance architecture"),
Column("os", TEXT, "The OS of this instance"),
Column("description", TEXT, "Instance description"),
Column("pid", INTEGER, "Instance's process ID"),
Column("processes", INTEGER, "Number of processes running inside this instance")
])
implementation("applications/lxd@genLxdInstances")
examples([
"select * from lxd_instances",
"select * from lxd_instances where name = 'hello'"
])

View File

@ -0,0 +1,21 @@
table_name("lxd_networks")
description("LXD network information.")
schema([
Column("name", TEXT, "Name of the network"),
Column("type", TEXT, "Type of network"),
Column("managed", INTEGER, "1 if network created by LXD, 0 otherwise"),
Column("ipv4_address", TEXT, "IPv4 address"),
Column("ipv6_address", TEXT, "IPv6 address"),
Column("used_by", TEXT, "URLs for containers using this network"),
Column("bytes_received", BIGINT, "Number of bytes received on this network"),
Column("bytes_sent", BIGINT, "Number of bytes sent on this network"),
Column("packets_received", BIGINT, "Number of packets received on this network"),
Column("packets_sent", BIGINT, "Number of packets sent on this network"),
Column("hwaddr", TEXT, "Hardware address for this network"),
Column("state", TEXT, "Network status"),
Column("mtu", INTEGER, "MTU size")
])
implementation("applications/lxd@genLxdNetworks")
examples([
"select * from lxd_networks"
])

View File

@ -0,0 +1,16 @@
table_name("lxd_storage_pools")
description("LXD storage pool information.")
schema([
Column("name", TEXT, "Name of the storage pool"),
Column("driver", TEXT, "Storage driver"),
Column("source", TEXT, "Storage pool source"),
Column("size", TEXT, "Size of the storage pool"),
Column("space_used", BIGINT, "Storgae space used in bytes"),
Column("space_total", BIGINT, "Total available storage space in bytes for this storage pool"),
Column("inodes_used", BIGINT, "Number of inodes used"),
Column("inodes_total", BIGINT, "Total number of inodes available in this storage pool")
])
implementation("applications/lxd@genLxdStoragePools")
examples([
"select * from lxd_storage_pools"
])